您的位置:首页 > 运维架构

理解Angular中的$scope

2015-11-20 01:22 274 查看

Angular scope 使用的一些问题总结

在AngularJS中,child scope一般通过原型式继承自它的parent scope。(directive的scope属性为{...}的情况除外,因为它会创建独立的scope)。在指令中,默认使用的是parent scope,这意味着在指令中改变的任何属性都会反映到其parent scope中。设置scope:true 会在该指令中使用原型继承。

scope的继承通常是直截了当的,但是当你尝试在child scope中使用定义在parent scope的双向数据绑定的时候,它可能就不像你期望的那样起作用了。原因是child scope会重写parent scope中的重名属性,这是原型式继承的一个特征。

注意:ng-repeat, ng-switch, ng-view, ng-include 都会创建新的child scope,上述问题通常出现在这些指令的使用过程中。具体可以看看这个例子

要避免上面的问题有以下几个方法:

总是在ng-model中使用 '.' 即ng-model使用一个对象而不是一个基本类型的值
这样:<input type="text" ng-model="someObj.prop1">
而不是: <input type="text" ng-model="prop1">

如果你实在要使用基本类型,可以参照下面两个方法
1.在child scope中使用 $parent.parentScopeProperty,它会阻止child scope创建自己的属性覆盖parent scope上的同名属性
2.在parent scope中定义一个方法,然后在child scope中调用,将基本类型值通过参数传递给parent

Angular scope 的继承

以下会创建新的scope,并且原型式继承自parent scope:
ng-repeat, ng-include, ng-switch, ng-view, ng-controller, 设置了scope: true的指令, 设置了transclude: true的指令

以下会创建新的scope,但是不通过原型式继承自parent scope
设置了 scope: {....}. 这样会创建一个独立的scope

注意,默认情况下,自定义指令并不会创建新的scope,scope:false是默认值

ng-include
假设在controller.js中有以下代码

// 定义一个基本类型的值
$scope.myPrimitive = 50;
// 定义一个对象
$scope.myObject    = {aNumber: 11};


html代码

<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都会产生一个新的child scope, 原型继承自parent scope





看看结果如下:



第一个input的ng-model是一个基本类型,它不能与parent scope中的表达式实现双向数据绑定,原因在于child scope通过原型继承属性自其parent scope,对于基本类型的值,child scope重写parent scope中的重名属性。



第二个input的ng-model是一个对象,它可以实现双向数据绑定,当ngModel查找一个对象时,它会一直查找到parent scope.





我们也可以对第一个input进行改写如下:

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




这里$parent是child scope下的一个属性,该属性指向parent scope

或者在parent scope中定义一个方法来改变基本类型的值,在child scope调用该方法,看代码

// controller.js
$scope.setMyPrimitive = function (value){
$scope.myPrimitive = value;
}


<input ng-model="myPrimitive" class="form-control" ng-change="setMyPrimitive(myPrimitive)">


效果如下:可以看到可以正常地进行双向数据绑定了



[b]ng-repeat[/b]
假设有如下代码:controller.js

$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects    = [{num: 101}, {num: 202}]


html代码如下:

<ul><li ng-repeat="num in myArrayOfPrimitives">
<input ng-model="num"></input>
</li>
</ul>
<ul><li ng-repeat="obj in myArrayOfObjects">
<input ng-model="obj.num"></input>
</li>
</ul>


对每一个li,ng-repeat都创建一个新的scope,继承自parent scope,但是同时会将遍历的变量(第一个ul中为num) 作为新的child scope的一个属性,myArrayOfPrimitives[num]的值作为该属性的属性值。

angular中ng-repeat的源码如下:

childScope = scope.$new(); // child scope prototypically inherits from parent scope ...
childScope[valueIdent] = value; // creates a new childScope property


如果在遍历数组中的每个item是一个基本类型(myArrayOfPrimitives),该item的值会被分配给新child scope的属性,改变这个属性的值(例如使用ng-model),不会改变parent scope中的数组。在第一个ul中,每个child scope有一个num属性独立于数组myArrayOfPrimitives。



如果我们希望改变在item中改变parent scope中的数组,我们需要将model变为一个数组对象

所以,如果数组中的每个item都是一个对象,该对象的一个引用会被分配给child scope的属性,改变child scope的属性值也会改变parent scope中的数组的引用。



今天先搞到这里,原文地址 Understanding Scopes
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: