ホームページ ウェブフロントエンド jsチュートリアル AngularJS フレームワークの Scope オブジェクトをさらに詳しく説明するスーパー チュートリアル_AngularJS

AngularJS フレームワークの Scope オブジェクトをさらに詳しく説明するスーパー チュートリアル_AngularJS

May 16, 2016 pm 03:22 PM
angularjs javascript

1. 問題が発生しました
この問題は、AngularJS を使用してコントローラーをネストするときに発生します。各コントローラーには対応するスコープ (スコープ、コントロール スコープに相当) があるため、コントローラーのネストはスコープのネストも意味します。このとき、両方のスコープに同じ名前のモデルがあった場合はどうなりますか?子スコープから親スコープのモデルを更新するにはどうすればよいですか?

この問題は非常に典型的なものです。たとえば、現在のページが製品リストの場合、ProductListController

を定義する必要があります。

1

2

3

4

5

6

7

function ProductListController($scope, $http) {

  $http.get('/api/products.json')

    .success(function(data){

      $scope.productList = data;

    });

  $scope.selectedProduct = {};

}

ログイン後にコピー

selectedProduct モデルもスコープで定義されており、特定の製品が選択されていることを示していることがわかります。このとき、製品の詳細が取得され、AngularJS の $routeProvider を通じてページが自動的に更新され、新しい詳細ページ テンプレートがプルされます。テンプレートには ProductDetailController

があります。

1

2

3

4

5

6

function ProductDetailController($scope, $http, $routeParams) {

  $http.get('/api/products/'+$routeParams.productId+'.json')

    .success(function(data){

      $scope.selectedProduct = data;

    });

}

ログイン後にコピー

興味深いことが起こりました。ここには selectedProduct もあります。これは ProductListController の selectedProduct にどのような影響を与えるでしょうか?

答えは「影響はない」です。 AnuglarJS では、子スコープは親スコープのオブジェクトを継承しますが、基本的なデータ型 (文字列、数値、ブール値) で双方向のデータ バインディングを試してみると、継承が想像どおりに行われないことがわかります。 . そのように動作します。子スコープのプロパティは、親スコープ内の同じ名前のプロパティを非表示 (上書き) し、子スコープ (フォーム要素) のプロパティを変更しても、親スコープ プロパティの値は更新されません。この動作は実際には AngularJS に固有のものではなく、JavaScript のネイティブ プロトタイプ チェーンはこのように動作します。開発者は、ng-repeat、ng-switch、ng-view、および ng-include がすべて新しい子スコープを作成することを認識していないことが多いため、これらのディレクティブを使用すると問題が発生することがよくあります。

2. 解決策
解決策は、基本的なデータ型を使用せず、常にモデルにドットを 1 つ追加することです。


を使用します

1

<input type="text" ng-model="someObj.prop1">

ログイン後にコピー


に置き換えます

1

<input type="text" ng-model="prop1">

ログイン後にコピー

それは非常に不正行為ではありませんか?以下の例は、私が表現したい奇妙な現象を明確に表現しています

1

2

3

4

5

6

7

8

9

app.controller('ParentController',function($scope){

  $scope.parentPrimitive = "some primitive"

  $scope.parentObj = {};

  $scope.parentObj.parentProperty = "some value";

});

app.controller('ChildController',function($scope){

  $scope.parentPrimitive = "this will NOT modify the parent"

  $scope.parentObj.parentProperty = "this WILL modify the parent";

});

ログイン後にコピー

オンラインデモ DEMO を見る
しかし、文字列数値などのプリミティブ データ型を本当に使用する必要がある場合はどうすればよいでしょうか? 2つの方法——

子スコープで $parent.parentPrimitive を使用します。 これにより、子スコープが独自のプロパティを作成できなくなります。
親スコープで関数を定義し、子スコープでその関数を呼び出し、元のデータ型パラメータを親に渡し、それによって親スコープのプロパティを更新します。 (常に可能というわけではありません)
3. JavaScript プロトタイプ チェーンの継承
暴言は終わったので、JavaScript のプロトタイプ チェーンを詳しく見てみましょう。これは、特にサーバーサイド開発からフロントエンドに移行する場合に重要です。古典的なクラスの継承についてよく知っている必要があるので、確認してみましょう。

親クラスparentScopeに次のメンバープロパティaString、aNumber、anArray、anObject、およびaFunctionがあるとします。サブクラス childScope プロトタイプは親クラスparentScope を継承するため、次のようになります:

201614150604637.png (619×257)

子のスコープがparentScopeで定義されたプロパティにアクセスしようとすると、JavaScriptはまず子スコープを検索します。そのようなプロパティが存在しない場合は、継承したスコープから継承するプロパティを探します。プロトタイプ オブジェクトparentScope にはプロパティ がないため、そのプロトタイプ内で検索を続け、rootScope に到達するまでプロトタイプ チェーンを遡っていきます。したがって、次の式の結果は true になります:

1

2

3

4

childScope.aString === 'parent string'

childScope.anArray[1] === 20

childScope.anObject.property1 === 'parent prop1'

childScope.aFunction() === 'parent output'

ログイン後にコピー

次のステートメントを実行するとします

1

childScope.aString = 'child string'

ログイン後にコピー

プロトタイプ チェーンはクエリされませんが、新しい属性 aString が childScope に追加されます。この新しいプロパティは、parentScope 内の同じ名前のプロパティを非表示 (オーバーライド) にします。この概念は、以下で ng-repeat と ng-include について説明するときに重要です。

201614150634794.png (619×257)

次の操作を実行するとします:

1

2

childScope.anArray[1] = '22'

childScope.anObject.property1 = 'child prop1'

ログイン後にコピー

オブジェクト anArray と anObject が childScope で見つからなかったため、プロトタイプ チェーンがクエリされました。それらはparentScopeで見つかり、値が更新されます。新しいプロパティは childScope に追加されず、新しいオブジェクトも作成されません。 (注: JavaScript では、配列と関数は両方ともオブジェクトです)

201614150658628.png (608×257)

次の操作を実行するとします:

1

2

childScope.anArray = [100, 555]

childScope.anObject = { name: 'Mark', country: 'USA' }

ログイン後にコピー

原型链没有被查询,并且子 Scope 新加入了两个新的对象属性,它们隐藏(覆盖)了 parentScope 中的同名对象属性。

201614150718718.png (608×320)

应该可以总结

如果读取 childScope.propertyX,并且 childScope 有属性 propertyX,那么原型链没有被查询。
如果设置 childScope.propertyX,原型链不会被查询。
最后一种情况,

1

2

delete childScope.anArray

childScope.anArray[1] === 22 // true

ログイン後にコピー

我们从 childScope 删除了属性,则当我们再次访问该属性时,原型链会被查询。删除对象的属性会让来自原型链中的属性浮现出来。

201614150741147.png (608×320)

四、AngularJS 的 Scope 继承
创建新的 Scope,并且原型继承:ng-repeat, ng-include, ng-switch, ng-view, ng-controller, directive with scope: true, directive with transclude: true
创建新的 Scope,但不继承:directive with scope: { ... }。它会创建一个独立 Scope。
注:默认情况下 directive 不创建新 Scope,即默认参数是 scope: false。

1

ng-include

ログイン後にコピー

假设在我们的 controller 中,

1

2

$scope.myPrimitive = 50;

$scope.myObject  = {aNumber: 11};

ログイン後にコピー

HTML 为:

1

2

3

4

5

6

7

8

9

<script type="text/ng-template" id="/tpl1.html">

  <input ng-model="myPrimitive">

</script>

<div ng-include src="'/tpl1.html'"></div>

  

<script type="text/ng-template" id="/tpl2.html">

  <input ng-model="myObject.aNumber">

</script>

<div ng-include src="'/tpl2.html'"></div>

ログイン後にコピー

每一个 ng-include 会生成一个子 Scope,每个子 Scope 都继承父 Scope。

201614151048789.png (541×115)

输入(比如”77″)到第一个 input 文本框,则子 Scope 将获得一个新的 myPrimitive 属性,覆盖掉父 Scope 的同名属性。这可能和你预想的不一样。

201614151107899.png (541×124)

输入(比如”99″)到第二个 input 文本框,并不会在子 Scope 创建新的属性,因为 tpl2.html 将 model 绑定到了一个对象属性(an object property),原型继承在这时发挥了作用,ngModel 寻找对象 myObject 并且在它的父 Scope 中找到了。

201614151132150.png (541×124)

如果我们不想把 model 从 number 基础类型改为对象,我们可以用 $parent 改写第一个模板:

1

<input ng-model="$parent.myPrimitive">

ログイン後にコピー

输入(比如”22″)到这个文本框也不会创建新属性了。model 被绑定到了父 scope 的属性上(因为 $parent 是子 Scope 指向它的父 Scope 的一个属性)。

201614151212469.png (541×117)

对于所有的 scope (原型继承的或者非继承的),Angular 总是会通过 Scope 的 $parent, $$childHead 和 $$childTail 属性记录父-子关系(也就是继承关系),图中为简化而未画出这些属性。

在没有表单元素的情况下,另一种方法是在父 Scope 中定义一个函数来修改基本数据类型。因为有原型继承,子 Scope 确保能够调用这个函数。例如,

1

2

3

// 父 Scope 中

$scope.setMyPrimitive = function(value) {

  $scope.myPrimitive = value;

ログイン後にコピー

查看 DEMO

ng-switch
ng-switch 的原型继承和 ng-include 一样。所以如果你需要对基本类型数据进行双向绑定,使用 $parent,或者将其改为 object 对象并绑定到对象的属性,防止子 Scope 覆盖父 Scope 的属性。
ng-repeat
ng-repeat 有一点不一样。假设在我们的 controller 里:

1

2

$scope.myArrayOfPrimitives = [ 11, 22 ];

$scope.myArrayOfObjects  = [{num: 101}, {num: 202}]

ログイン後にコピー

还有 HTML:

1

2

3

4

5

6

7

8

9

10

<ul>

  <li ng-repeat="num in myArrayOfPrimitives">

    <input ng-model="num">

  </li>

<ul>

<ul>

  <li ng-repeat="obj in myArrayOfObjects">

    <input ng-model="obj.num">

  </li>

<ul>

ログイン後にコピー

对于每一个 Item,ng-repeat 创建新的 Scope,每一个 Scope 都继承父 Scope,但同时 item 的值也被赋给了新 Scope 的新属性(新属性的名字为循环的变量名)。Angular ng-repeat 的源码实际上是这样的:

1

2

childScope = scope.$new(); // 子 scope 原型继承父 scope ...  

childScope[valueIdent] = value; // 创建新的 childScope 属性

ログイン後にコピー

如果 item 是一个基础数据类型(就像 myArrayOfPrimitives),本质上它的值被复制了一份赋给了新的子 scope 属性。改变这个子 scope 属性值(比如用 ng-model,即 num)不会改变父 scope 引用的 array。所以上面第一个 ng-repeat 里每一个子 scope 获得的 num 属性独立于 myArrayOfPrimitives 数组:

201614151333896.png (440×153)

这样的 ng-repeat 和你预想中的不一样。在 Angular 1.0.2 及更早的版本,向文本框中输入会改变灰色格子的值,它们只在子 Scope 中可见。Angular 1.0.3+ 以后,输入文本不会再有任何作用了。
我们希望的是输入能改变 myArrayOfPrimitives 数组,而不是子 Scope 里的属性。为此我们必须将 model 改为一个关于对象的数组(array of objects)。

所以如果 item 是一个对象,则对于原对象的一个引用(而非拷贝)被赋给了新的子 Scope 属性。改变子 Scope 属性的值(使用 ng-model,即 obj.num)也就改变了父 Scope 所引用的对象。所以上面第二个 ng-repeat 可表示为:

201614151355015.png (560×152)

这才是我们想要的。输入到文本框即会改变灰色格子的值,该值在父 Scope 和子 Scope 均可见。
ng-controller
使用 ng-controller 进行嵌套,结果和 ng-include 和 ng-switch 一样是正常的原型继承。所以做法也一样不再赘述。然而“两个 controller 使用 $scope 继承来共享信息被认为是不好的做法”
应该使用 service 在 controller 间共享数据。

如果你确实要通过继承来共享数据,那么也没什么特殊要做的,子 Scope 可以直接访问所有父 Scope 的属性。
directives
这个要分情况来讨论。

默认 scope: false – directive 不会创建新的 Scope,所以没有原型继承。这看上去很简单,但也很危险,因为你会以为 directive 在 Scope 中创建了一个新的属性,而实际上它只是用到了一个已存在的属性。这对编写可复用的模块和组件来说并不好。
scope: true – 这时 directive 会创建一个新的子 scope 并继承父 scope。如果在同一个 DOM 节点上有多个 directive 都要创建新 scope,则只有一个新 Scope 会创建。因为有正常的原型继承,所以和 ng-include, ng-switch 一样要注意基础类型数据的双向绑定,子 Scope 属性会覆盖父 Scope 同名属性。
scope: { ... } – 这时 directive 创建一个独立的 scope,没有原型继承。这在编写可复用的模块和组件时是比较好的选择,因为 directive 不会不小心读写父 scope。然而,有时候这类 directives 又经常需要访问父 scope 的属性。对象散列(object hash)被用来建立这个独立 Scope 与父 Scope 间的双向绑定(使用 ‘=')或单向绑定(使用 ‘@')。还有一个 ‘&' 用来绑定父 Scope 的表达式。这些统统从父 Scope 派生创建出本地的 Scope 属性。注意,HTML 属性被用来建立绑定,你无法在对象散列中引用父 Scope 的属性名,你必须使用一个 HTML 属性。例如,

和 scope: { localProp: '@parentProp' } 是无法绑定父属性 parentProp 到独立 scope的,你必须这样指定:
以及 scope: { localProp: '@theParentProp' }。独立的 scope 中 __proto__ 引用了一个 Scope 对象(下图中的桔黄色 Object),独立 scope 的 $parent 指向父 scope,所以尽管它是独立的而且没有从父 Scope 原型继承,它仍然是一个子 scope。

下面的图中,我们有 和 scope:

1

{ interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }。

ログイン後にコピー

同时,假设 directive 在它的 link 函数里做了 scope.someIsolateProp = "I'm isolated"

201614151506832.png (467×157)

注意:在 link 函数中使用 attrs.$observe('attr_name', function(value) { ... } 来获取独立 Scope 用 ‘@' 符号替换的属性值。例如,在 link 函数中有 attrs.$observe('interpolated', function(value) { ... } 值将被设为 11. (scope.interpolatedProp 在 link 函数中是 undefined,相反scope.twowayBindingProp 在 link 函数中定义了,因为用了 ‘=' 符号)
transclude: true – 这时 directive 创建了一个新的 “transcluded” 子 scope,同时继承父 scope。所以如果模板片段中的内容(例如那些将要替代 ng-transclude 的内容)要求对父 Scope 的基本类型数据进行双向绑定,使用 $parent,或者将 model 一个对象的属性,防止子 Scope 属性覆盖父 Scope 属性。

transcluded 和独立 scope (如果有)是兄弟关系,每个 Scope 的 $parent 指向同一个父 Scope。当模板中的 scope 和独立 Scope 同时存在,独立 Scope 属性 $$nextSibling 将会指向模板中的 Scope。
在下图中,假设 directive 和上个图一样,只是多了 transclude: true

201614151536198.png (640×226)

查看 在线 DEMO,例子里有一个 showScope() 函数可以用来检查独立 Scope 和它关联的 transcluded scope。
总结
一共有四种 Scope:

普通进行原型继承的 Scope —— ng-include, ng-switch, ng-controller, directive with scope: true
普通原型继承的 Scope 但拷贝赋值 —— ng-repeat。 每个 ng-repeat 的循环都创建新的子 Scope,并且子 Scope 总是获得新的属性。
独立的 isolate scope —— directive with scope: {...}。它不是原型继承,但 ‘=', ‘@' 和 ‘&' 提供了访问父 Scope 属性的机制。
transcluded scope —— directive with transclude: true。它也遵循原型继承,但它同时是任何 isolate scope 的兄弟。
对于所有的 Scope,Angular 总是会通过 Scope 的 $parent, $$childHead 和 $$childTail 属性记录父-子关系。

PS:scope和rootscope的区别
scope是html和单个controller之间的桥梁,数据绑定就靠他了。rootscope是各个controller中scope的桥梁。用rootscope定义的值,可以在各个controller中使用。下面用实例详细的说明一下。
1,js代码

1

2

3

4

5

6

7

8

9

10

11

phonecatApp.controller('TestCtrl',['$scope','$rootScope',

  function($scope,$rootScope) {

    $rootScope.name = 'this is test';

  }

]);

  

phonecatApp.controller('Test111Ctrl',['$scope','$rootScope',

  function($scope,$rootScope) {

    $scope.name = $rootScope.name;

  }

]);

ログイン後にコピー

2,html代码

1

2

3

4

5

6

7

8

<div ng-controller="TestCtrl">

  I set the global variable.<strong>{{$root.name}}</strong>

</div>

  

<div ng-controller="Test111Ctrl">

  1,get global variable .<strong>{{name}}</strong><br>

  2,get global variable .<strong>{{$root.name}}</strong>

</div>

ログイン後にコピー

3,显示结果

1

2

3

I set the global variable.this is test

1,get global variable .this is test

2,get global variable .this is test

ログイン後にコピー

由结果可以看出来,$rootScope.name设置的变量,在所有controller里面都是可以直接用{{$root.name}}来显示的,很强大。那当然也可以赋值给scope.
 

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 Dec 17, 2023 am 08:41 AM

JavaScript は Web 開発で広く使用されているプログラミング言語であり、WebSocket はリアルタイム通信に使用されるネットワーク プロトコルです。 2 つの強力な機能を組み合わせることで、効率的なリアルタイム画像処理システムを構築できます。この記事では、JavaScript と WebSocket を使用してこのシステムを実装する方法と、具体的なコード例を紹介します。まず、リアルタイム画像処理システムの要件と目標を明確にする必要があります。リアルタイムの画像データを収集できるカメラ デバイスがあるとします。

See all articles