Angularのサービスの中にはngの中核とも言えるサービスがいくつかありますので、今日はngの2つのコアサービスである$parseと$compileを紹介したいと思います。実際、多くの人がこれら 2 つのサービスについて話しますが、100 人の読者ごとに 100 人のハムレットが存在します。私はこれら 2 つのサービスについての私の理解をここで話したいと思います。
疑問があるかもしれませんが、$eval は実際にはサービスではなく、スコープ内のメソッドであり、サービスとみなされません。また、これも parse に基づいているため、別の書き方としか考えられません。 $parse. ng ソースコードの $eval の定義を見てみましょう
$eval: function(expr, locals) { return $parse(expr)(this, locals); },
ソースコードを読めば皆さんも理解できると思います。私の発言が間違っていると思われる場合は、他の読者を傷つけないように、コメント欄またはプライベートチャットでお気軽に指摘してください。
これら 2 つのサービスについて説明するとき、この記事ではまずコンテキストについて説明します。
この「コンテキスト」について聞いたことがある人は多いと思いますが、少し漠然としているかもしれませんので説明させてください。皆さんがこの声明を受け入れるかどうか見てみましょう。
Angular のデータ バインディングをまだ覚えていますか?例: 今、TestCtrl というコントローラーがあり、その内容は次のとおりです:
.controller('TestCtrl', function($scope) { $scope.test = "Boo!!!" })
そして、HTML のコードは次のようになります
<body ng-controller="TestCtrl"> {{test}} </body>
まあ、誰もが考えずにそれを知っています 結果として、「Boo!!!」という文字がページに必ず表示されます。
しかし、ng-controller ディレクティブを削除したらどうなるでしょうか?つまり、HTML でコントローラーを宣言しなかった場合、{{test}} を直接バインドするとどうなりますか?
結果は 1 つだけです。つまり、ページには何もありません (追記: ng-app を宣言したため)。これわかりますか?
コントローラーはコンテキスト コンテナーに相当します。実際のコンテキストは $scope です。ページがテストにバインドされている場合、コントローラーが宣言されている場合、現在のコンテキストはコントローラー内の $scope です。コントローラーのコンテキスト $scope にはテストが含まれていますか? あれば当然表示されますが、コントローラーを宣言しない場合はどうなるでしょうか?彼のコンテキスト コンテナは ng-app であり、実際のコンテキストは $rootScope です。この時点で、テストがあるかどうかを確認するために $rootScope を探します。
さて、コンテキストの概念についての説明は終わりました。これは基本的にこれと非常に似ています
それでは、本題に入りましょう。最初に必要なことを始めましょう。参照するのは ng の API ドキュメントです
var getter = $parse('user.name'); var setter = getter.assign; var context = {user:{name:'angular'}}; var locals = {user:{name:'local'}}; expect(getter(context)).toEqual('angular'); setter(context, 'newValue'); expect(context.user.name).toEqual('newValue'); expect(getter(context, locals)).toEqual('local');
表示されているのは、ng ドキュメント内の $parse サービスの最もコスト効率の高いコード行です
getter と setter はよく知られた get メソッドと set です。 context と locals は単なる json オブジェクトであり、目的はコンテキスト関係をシミュレートすることです
分析する前に、これらのステートメントを 1 つずつ分析していきます。 $parse は
$parse サービスは、実際には ng-model="test" と同様に、これを HTML で記述すると、 ng-model="test" であることを誰にもわかりません。バインドしたいものは、現在のコントローラー (コンテキスト コンテナー) のスコープ (コンテキスト) 内にあります。 test の値の場合、ng は $parse サービスを使用して式の解析を支援します。そのため、$parse サービスを呼び出すときは、次のことを行う必要があります。このテストでどこに行きたいかを知らせるためにコンテキスト オブジェクトを渡します。
したがって、テスト コードの最初の行は次のようになっていることがわかります:
getter(context)).toEqual('angular') //实际上就是 $parse('user.name')(context)
このコンテキストでは、「angular」文字列を返す原理は次の 3 つのステップを通じて行われます。現在の式 user.name を取得します
2. 現在のコンテキスト オブジェクト {user:{name:'angular'}} を取得します
3. 上部と下部のオブジェクトで式を検索し、最後に作成された文字「angular」を取得します。
つまり、このテストコードは成功しました。
2 番目のメソッドであるセッター メソッドを見てみましょう
ここでのセッター メソッドは実際には値の変更メソッドです
1. 現在の式 user.name を取得します
2. 現在のコンテキスト オブジェクトを取得します
user: {name:'angular'}}
3. 式の値を変更し、コンテキスト オブジェクトをプログラムします {user:{name:'newValue'}}
その後、コンテキスト オブジェクトが変更され、getter メソッドを再利用して取得します式の式、コンテキストは {user:{name:'angular'}} --> {user:{name:'newValue'}} から変更され、最終的に取得される式の値は当然 "newValue" になります。なので、テスト コードも合格しました。
setter(context, 'newValue');//实际上就是 $parse('user.name').assign(context, 'newValue') expect(context.user.name).toEqual('newValue');//测试数据上下文的值是否被改变
ここで紹介したいのは、実際にはコンテキスト置換関数です。
getter メソッドでは、最初のコンテキストを選択するだけでなく、2 番目のパラメーターを渡すと、最初のコンテキストが 2 番目のコンテキストによって上書きされることに注意してください。
1. user.name の式
2. 現在のコンテキスト オブジェクト {user:{name:'angular'}} を取得します
3. 現在のコンテキスト {user:{name:'local'}} を取得します。解析後の式の値
$eval に戻ると、$eval のソース コードから、$eval には get 関数のみがあり、set 関数はありませんが、値を変更する効果を実現するために 2 番目のコンテキストを渡すことを選択できる場合があります。
$parse サービスはここで終了し、次のステップは $compile です
---------------------------- --- -------------------
$parse の概念が理解できれば、$compile もほぼ理解できると思います。 $解析。ただし、これは HTML コードの一部を解析し、その機能は無効なテンプレートをライブ テンプレートに変換することであり、これがコマンドのコア サービスでもあります。
たとえば、HTML コード
$compile('dead template') (コンテキスト オブジェクト)、この方法で、デッド テンプレートがライブ テンプレートにプログラムされ、このライブ HTML コードに対して現在のノードへの追加などの操作を実行できます。 。
しかし、命令では、リンク前とリンク後の 2 つの関数を返します
最初に実行される関数はリンク前であり、同じ命令の走査順序は親ノードから子ノードへです。この段階では、DOM ノードはまだ安定していないため、一部のバインディング イベント操作を実行できませんが、ここでいくつかの初期データ処理を実行できます。
2 番目に実行されるのはポストリンクです。これは、子ノードから親ノードに移動するものであり、通常は多くの作業が行われます。ここで操作。