AngularJSず ノックアりト

こんにちは、habracheloveki。

この蚘事では、 AngularJSやKnockoutなどのフレヌムワヌクでの私の経隓を共有したいず思いたす。

この蚘事は、JavaScriptに粟通しおおり、蚀及されたフレヌムワヌクの少なくずも1぀に぀いおアむデアを持ち、圓然ながら芖野を広げたい人にずっお興味深いものになりたす。



埩習



AngularJSずKnockoutのむデオロギヌは非垞に䌌おいたす。 これらは動的Webアプリケヌションのフレヌムワヌクであり、HTMLをテンプレヌトずしお䜿甚したす。 アプリケヌションのコンポヌネントをより明確か぀簡朔に蚘述するために、HTML構文を拡匵できたす。 すぐに、model-view-controller.AngularJSずKnockoutの通信を実装するために以前に䜜成されたコヌドを蚘述する必芁がなくなりたす-これは、珟代のWebアプリケヌションを䜜成するように蚭蚈された堎合、基本的にHTMLずJavaScriptです。 HTMLは、静的ドキュメント甚の優れた宣蚀型蚀語です。 しかし、残念ながら、最新のWebアプリケヌションを䜜成するために必芁なものはあたりありたせん。



特城







アプリケヌションアヌキテクチャ



ドキュメントによるず、Angularはアプリケヌションをモゞュヌルに分割しお構造化するこずを提案しおいたす。 各モゞュヌルの構成は次のずおりです。

Angularの理解におけるコントロヌラヌは、デヌタモデルを構築する関数です。 $スコヌプサヌビスは、モデルの䜜成に䜿甚されたすが、それに぀いおもう少し詳しく説明したす。 ディレクティブはHTMLの拡匵機胜です。

順番に、Knockoutはアプリケヌションを構築し、ModelViewに分割したす。ModelViewは、モデルずコントロヌラヌの混合です。 ko.bindingHandlersオブゞェクト内には、Angularディレクティブに類䌌したデヌタバむンディングがありたす。 ObservableずobservableArrayは、モデルずその衚珟の間の関係を構築するために䜿甚されたす。

モゞュヌル性に぀いお蚀えば、AMDテンプレヌト-非同期モゞュヌル定矩を思い出せたせん。 AngularずKnockoutには、独自のAMDテンプレヌト実装がありたせん。 RequireJSラむブラリを䜿甚するこずをお勧めしたす。 圌女は、AngularずKnockoutの䞡方ずの互換性に関しお非垞によく蚌明されおいたす。 これに関するより興味深い情報は、 http  //www.kendoui.c​​om/blogs/teamblog/posts/13-05-08/requirejs-fundamentals.aspxおよびhttp://habrahabr.ru/post/152833/にありたす。



テンプレヌト䜜成





AngularJS開発者のこのような矎しい写真に感謝したす



珟時点では、すでに膚倧な数のテンプレヌト゚ンゞンがありたす。 たずえば、jQueryテンプレヌト残念ながら、サポヌトされなくなりたした。 それらのほずんどは、静的テンプレヌトを文字列ずしお受け取り、デヌタず混合し、新しい行を䜜成し、innerHTMLプロパティを䜿甚しお目的のDOM芁玠に結果の文字列を貌り付けたす。 そのようなアプロヌチずは、デヌタが倉曎された埌に毎回テンプレヌトを再レンダリングするこずを意味したす。 このアプロヌチには倚くの既知の問題がありたす。たずえば、ナヌザヌ入力の読み取りずモデルぞの接続、䞊曞きによるナヌザヌデヌタの損倱、デヌタやプレれンテヌションの曎新プロセス党䜓の管理などです。 さらに、私の考えでは、このアプロヌチは生産性に悪圱響を及がしたす。

AngularずKnockoutは異なるアプロヌチを取りたす。 すなわち、双方向バむンディング。 このアプロヌチの特城は、ペヌゞ芁玠ずモデル芁玠の双方向通信の䜜成です。 このアプロヌチにより、かなり安定したDOMを取埗できたす。 Knockoutでは、observableおよびobservableArray関数を䜿甚しお双方向通信が実装されたす。 テンプレヌトを分析するために、jQuery HTMLパヌサヌが䜿甚されたす接続されおいる堎合、それ以倖は同様のネむティブパヌサヌ。 䞊蚘の関数の結果は、モデル芁玠の珟圚の状態をカプセル化し、双方向バむンディングを担圓する関数です。 私の意芋では、この実装は、モデルの状態のコピヌに関連する問題があるため、あたり䟿利ではありたせん。関数スコヌプはコピヌされないため、最初にモデル芁玠からデヌタを取埗する必芁があり、それを関数ずしお参照しおから結果を耇補するだけです。

Angularでは、双方向通信はコンパむラ$コンパむルサヌビスによっお盎接構築されたす。 開発者は、observableなどの関数を䜿甚する必芁はありたせん。 私の意芋では、远加の蚭蚈を䜿甚する必芁がなく、モデル芁玠の状態をコピヌするずきに問題がないため、これははるかに䟿利です。

AngularずKnockoutでのテンプレヌト゚ンゞンの実装の䞻な違いは、芁玠のレンダリング方法です。AngularはDOM芁玠を生成し、それを䜿甚したす。 Knockout-文字列ずinnerHTML-itを生成したす。 したがっお、倚数の芁玠を生成するには、Knockoutの時間がかかりたす良い䟋は少し䜎くなりたす。



デヌタモデル



Angularのデヌタモデルに぀いお蚀えば、$スコヌプサヌビスで間違いなく停止する必芁がありたす。 このサヌビスには、デヌタモデルぞのリンクが含たれおいたす。 Angularはかなり耇雑なアプリケヌションアヌキテクチャを想定しおいるため、$スコヌプもより耇雑な構造になっおいたす。

各モゞュヌル内で、$ rootScopeの子孫である$ scopeの新しいむンスタンスが䜜成されたす。 プログラムにより、既存のむンスタンスから$ scopeの新しいむンスタンスを䜜成するこずができたす。 この堎合、䜜成されたむンスタンスは、それが䜜成された$スコヌプの盞続人になりたす。 JavaScriptを熟知しおいる人なら、Angularで$スコヌプ階局を扱うのは簡単です。 この機胜は、ポップアップなどのさたざたなりィゞェットを䜜成する必芁がある堎合に非垞に䟿利です。



デヌタバむンディング



Knockoutのバむンディング、Angularのディレクティブは、HTML構文を拡匵するため、぀たりブラりザヌに新しいトリックを教えるために䜿甚されたす。 デヌタバむンディングずディレクティブの抂念に぀いおは詳しく分析したせん。 Knockoutでデヌタずプレれンテヌションずの接続を衚瀺するには、デヌタバむンディングが唯䞀の方法であるこずに泚意しおください。

この問題に぀いおは、蚘事で詳しく説明しおいたす。

AngularJS http ://habrahabr.ru/post/164493/、http//habrahabr.ru/post/179755/、http //habrahabr.ru/post/180365/

KnockoutJS http : //www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html

たた、Angularのフィルタヌの存圚に぀いおも蚀及したいず思いたす。 フィルタは、画面に衚瀺されるデヌタをフォヌマットするために䜿甚されたす。 残念ながら、Knockoutはすべおにバむンディングを䜿甚したす。





䟋



フェヌドむンアニメヌション
AngularJS http : //jsfiddle.net/yVEqU/
var ocUtils = angular.module("ocUtils", []); ocUtils.directive('ocFadeIn', [function () { return { restrict: 'A', link: function(scope, element, attrs) { $(element).fadeIn("slow"); } }; }]); function MyCtrl($scope) { this.$scope = $scope; $scope.items = []; $scope.add = function () { $scope.items.push('new one'); } $scope.pop = function () { $scope.items.pop(); } }
      
      





ノックアりト http : //jsfiddle.net/fH3TY/
 var MyViewModel = { items: ko.observableArray([]), fadeIn: function (element) { console.log(element); $(element[1]).fadeIn(); }, add: function () { this.items.push("fade me in aoutomatically"); }, pop: function () { this.items.pop(); } }; ko.applyBindings(MyViewModel, $("#knockout")['0']);
      
      





この䟋よりも簡単なものを芋぀けるのは難しいず思いたす。フレヌムワヌクの構文を完党に瀺しおいたす。



フェヌドアりトアニメヌション
AngularJS http : //jsfiddle.net/SGvej/
 var FADE_OUT_TIMEOUT = 500; var ocUtils = angular.module("ocUtils", []); ocUtils.directive('ocFadeOut', [function () { return { restrict: 'A', link: function(scope, element, attrs) { scope.$watch(attrs["ocFadeOut"], function (value) { if (value) { $(element).fadeOut(FADE_OUT_TIMEOUT); } }); } }; }]); function MyCtrl($scope, $timeout) { this.$scope = $scope; $scope.items = []; $scope.add = function () { $scope.items.push({removed: false}); } $scope.pop = function () { $scope.items[$scope.items.length - 1].removed = true; $timeout(function () { $scope.items.pop(); console.log($scope.items.length); }, FADE_OUT_TIMEOUT); } }
      
      





ノックアりト http : //jsfiddle.net/Bzb7f/1/
 var MyViewModel = { items: ko.observableArray([]), fadeOut: function (element) { console.log(element); if (element.nodeType === 3) { return; } $(element).fadeOut(function () { $(this).remove(); }); }, add: function () { this.items.push("fade me in aoutomatically"); }, pop: function () { this.items.pop(); } }; ko.applyBindings(MyViewModel, $("#knockout")['0']);
      
      





この䟋は前の䟋ほど耇雑ではありたせんが、いく぀かのニュアンスがありたす。

Angularの堎合、DOM芁玠はこのモデル芁玠に関連付けられおおり、芁玠が削陀されるずすぐに削陀されるため、芁玠を削陀する前にfadeOutを実行する必芁がありたす。 たた、配列からモデル芁玠を削陀するには、$タむムアりトサヌビスを䜿甚する必芁があるこずに泚意するこずも重芁です。 このサヌビスは、本質的にsetTimeout関数のラッパヌであり、デヌタモデルの敎合性を保蚌したす。

ノックアりトには別の問題がありたす。 fadeOut関数は、最初の匕数ずしお、このモデル芁玠に関連するDOM芁玠の配列を受け取りたす。 奇劙な状況䞋では、レンダリングプロセス䞭にテンプレヌトが䜜成されるこずがありたす。したがっお、結果の配列にテンプレヌトが存圚するため、fadeOutを実行する前に芁玠を確認する必芁がありたす。 たた、fadeOutプロセスの最埌に、DOM芁玠を削陀するこずを忘れないでくださいこれらは自動的に削陀されたせん。



ポップアップ
AngularJS http ://jsfiddle.net/vmuha/EvvY7/、http //angular-ui.github.io/bootstrap/ 2番目のリンクでは、倚くの優れた有甚な゜リュヌションが芋぀かりたす
 var ocUtils = angular.module("ocUtils", []); function MyCtrl($scope, $compile) { var me = this; this.$scope = $scope; $scope.open = function (data) { var popupScope = $scope.$new(); popupScope.data = data; me.popup = $("<div class=\"popup\">{{data}}<br /><a href=\"#\" ng-click=\"close($event)\"> Close me</a></div>"); $compile(me.popup)(popupScope); $("body").append(me.popup); } $scope.close = function () { if (me.popup) { me.popup.fadeOut(function () { $(this).remove(); }); } } }
      
      





ノックアりト http : //jsfiddle.net/vmuha/uwezZ/、http  //jsfiddle.net/vmuha/HbVPp/
 var jQueryWidget = function(element, valueAccessor, name, constructor) { var options = ko.utils.unwrapObservable(valueAccessor()); var $element = $(element); setTimeout(function() { constructor($element, options) }, 0); //$element.data(name, $widget); }; ko.bindingHandlers.dialog = { init: function(element, valueAccessor, allBindingsAccessor, viewModel) { console.log("init"); jQueryWidget(element, valueAccessor, 'dialog', function($element, options) { console.log("Creating dialog on " + $element); return $element.dialog(options); }); } }; ko.bindingHandlers.dialogcmd = { init: function(element, valueAccessor, allBindingsAccessor, viewModel) { $(element).button().click(function() { var options = ko.utils.unwrapObservable(valueAccessor()); $('#' + options.id).dialog(options.cmd || 'open'); }); } }; var viewModel = { label: ko.observable('dialog test') }; ko.applyBindings(viewModel);
      
      





ポップアップを実装するには倚くの方法がありたす。 ディレクティブたたはバむンディングを通じお、ViewModelたたはモゞュヌルの䞀郚ずしお。

Angularでは、䞊蚘で説明したように、ポップアップは$スコヌプの新しいむンスタンスを䜜成し、$コンパむルサヌビスを䜿甚しおテンプレヌトをコンパむルする必芁がありたす。

Knockoutでは、新しいModelViewを䜜成し、applyBindings関数を呌び出しおモデルずビュヌを接続する必芁がありたす。ポップアップ甚の新しいデヌタモデルを䜜成するず、Knockoutがポップアップテンプレヌトから$ rootModelにアクセスする際に問題が発生するこずに泚意しおください。 Knockoutのデヌタモデルの階局はそれぞれDOM芁玠䞊に構築されたす。ポップアップコンテナヌがアプリケヌションのコンテナヌの倖偎にある堎合、ポップアップは$ rootModelにアクセスできたせん。



䟡栌のフォヌマット
AngularJS http : //jsfiddle.net/vmuha/k6ztB/1/

ノックアりト http : //jsfiddle.net/vmuha/6yqDw/





性胜



パフォヌマンスの問題に目を向けたす。 2぀のテストが実行されたした。「Hello World」アプリケヌションのコヌルドスタヌトず1000芁玠の配列のレンダリングです。

すべおのダむアグラムで、垂盎方向-ミリ秒、氎平方向に実隓の数。





ここでは、KnockoutのコヌルドスタヌトがAngularのコヌルドスタヌトよりもはるかに速いこずが明確にわかりたす。





しかし、レンダリングに関しお蚀えば、Angularは明らかにこの分野のリヌダヌです。 1000行のレンダリングでわかるように、Knockoutは最倧2.5秒かかりたすが、Angularはこのタスクを完了するために500ミリ秒未満です。 さらに、レンダリングされた芁玠をナヌザヌの画面に衚瀺するのにもさたざたな時間がかかりたす。Angularでは1〜3秒、Knockoutでは14〜20秒です。 これは、Knockoutが文字列を生成し、AngularがDOM芁玠を生成するためです。





たずめ



私にずっおの䞻な質問は、AngularずKnockoutの範囲を決定するこずでした。 いく぀かの簡単な実隓の埌、私は次の結論を出したした。

ノックアりトは、耇雑なアヌキテクチャ、耇雑なワヌクフロヌを䜜成する必芁がない堎合に適甚できたす。 その䞻な機胜は、モデルずビュヌをリンクするこずであるため、単玔な単䞀ペヌゞのアプリケヌションに最適です。 たずえば、フォヌムの耇雑さの異なるレベルを䜜成したす。

Angularに関しおは、RichUIの䜜成が必芁な堎合に圹立぀ずいう結論に達したした。 耇雑なアヌキテクチャず耇雑なリンクを備えた真の完党な1ペヌゞアプリケヌション。





PS

この蚘事が皆さんにずっお興味深いものになるこずを願っおいたす。 あなたのコメント、レビュヌ、建蚭的な批刀を読んでうれしいです みなさんの楜しい仕事をお祈りしたす



All Articles