如何理解Angular自定义指令directive的scope属性?
分享人:聂义中
目录
1.背景介绍
2.知识剖析
3.常见问题
4.解决方案
5.编码实战
6.扩展思考
7.参考文献
8.更多讨论
1.背景介绍
在AngularJS中,内置指令如ng-click等并不能完全满足我们的开发需求,所以我们还需要自定义指令去满足其他的功能需求。 自定义指令,是为了扩展DOM元素的功能。代码中,通过指定directive中的restrict属性,来决定这个指令是作为标签 (E)、属性(A)、属性值(C)、还是注释(M)。 指令的定义过程就不详述了,可以参考其余小课堂。今天主要讲一下自定义指令中scope属性取值的区别。
2.知识剖析
scope这个属性用来修饰指令的作用域。 每当一个指令被创建的时候,都会有这样一个选择,是直接使用父作用域? 还是创建一个从父作用域继承的子作用域? 又或者是创建一个隔离的作用域(不依赖外部的作用域)?
scope属性的3种取值
1、false(默认值):直接使用父scope。
2、true:继承父scope
3、对象{}:创建一个新的“隔离”scope,但仍可与父scope通信
隔离的scope,通常用于创建可复用的指令,也就是它不用管父scope中的model。 然而虽然说是“隔离”,但通常我们还是需要让这个子scope跟父scope中的变量进行绑定。绑定的策略有3种:
@:单向绑定,外部scope能够影响内部scope,但反过来不成
=:双向绑定,外部scope和内部scope的model能够相互改变
&:把内部scope的函数的返回值和外部scope的任何属性绑定起来
3.常见问题
scope属性的3种取值的具体影响
4解决方案
1、false(默认值):直接使用父scope。比较“危险”。
可以理解成指令内部并没有一个新的scope,它和指令以外的代码共享同一个scope。 我们创建的指令继承了父作用域的一切属性和方法,这也 使得在指令的模板中我们可以使用这些属性和方法。
因为我们将scope的属性设置为false所以,我们创建的指令继承了父作用域的一切属性和方法, 这也使得在指令的模板中我们可以使用这些属性和方法。
2、true:继承父scope
当把scope属性设置为true时,这表明我们创建的指令要创建一个新的作用域,这个作用域继承自我们的父作用域。
一开始是绑定在父scope中,但当修改位于自定义指令中的输入框时,子scope就被创建并继承父scope了。 之后,修改父scope并不能影响input的值,而修改子scope就可以改变input的值了。
1、当我们将scope设置为false的时候,我们创建的指令和父作用域(其实是同 一个作用域)共享同一个model模型,所以在指令中修改模型数据 ,它会反映到父作用域的模型中。 2、当我们将scope设置为true的时候,我们就新创建了一个作用域, 只不过这个作用域是继承了我们的父作用域;我觉得可以这样理解, 我们新创建的作用域是一个新的作用域,只不过在初始化的时候, 用了父作用域的属性和方法去填充我们这个新的作用域。它和父作用域不是同一个作用域。
3、{}:创建一个新的“隔离”scope,当我们将scope的属性设置为{}时,我们可以做更多的事情。
AngularJS最强的大的地方之一就是它可以构建组件,无论放在哪里都是可以使用的; 这所以可以做到这些,不得不归功于指令的这个属性; 当我们将scope设置为{}时,意味着我们 创建的一个新的与父作用域隔离的新的作用域,这使我们在不知道外部环境的情况下, 就可以正常工作,不依赖外部环境。
所以隔离的scope,通常用于创建可复用的指令,也就是它不用管父scope中的model。
我们使用了隔离的作用域,不代表我们不可以使用父作用域的属性和方法。 我们可以通过向scope的{}中传入特殊的前缀标识符(即prefix),来进行数据的绑定。 在创建了隔离的作用域,我们可以通过@,&,=引用应用指令的元素的属性。 绑定的策略有3种:@、=、&
1、@
单项绑定的前缀标识符
使用方法:在元素中使用属性,好比这样<divmy-directivemy-name="{{name}}"></div>, 注意,属性的名字要用-将两个单词连接,因为是数据的单项绑定所以要通过使用{{}}来绑定数据。
2、=
双向数据绑定前缀标识符
使用方法:在元素中使用属性,好比这样<divmy-directiveage="age"></div>
,注意,数据的双向绑定要通过=前缀标识符实现,所以不可以使用{{}}。
aria-hidden="true">
3、&;
绑定函数方法的前缀标识符
使用方法:在元素中使用属性,好比这样<divmy-directivechange-my-age="changeAge()"></div>, 注意,属性的名字要用-将多个个单词连接。
5.编码实战
6.扩展思考
我们的指令是如何利用这些前缀标识符来寻找我们想要的属性或者函数的?
@当指令编译到模板的name时,就会到scope中寻找是否含有name的键值对,如果存在,就像上面那样,看到@就知道 这是一个单向的数据绑定,然后寻找原来的那个使用指令的元素上(或者是指令元素本身)含有这个值的属性即my-name={{name}}, 然后在父作用域查找{{name}}的值,得到之后传递给模板中的name。
=和&与@差不多,只不过=进行的是双向的数据绑定,不论模板还是父作用域上的属性的值发生改变都会使另一个值发生改变,而&是绑定函数而已。
7.参考文献
参考一:AngularJS自定义指令directive:scope属性
参考二:一招制敌 -玩转 AngularJS指令的 Scope(作用域)
8更多讨论
1 自定义指令作用域scope 属性值标识符&、= 、@后面接的是什么?
解答:标识符后面接的孤立作用域属性名,因为孤立作用域属性名可以与父作用域属性名不一样,这个时候只需要把属性名接在标识符后面。
2 为什么隔离作用域scope不直接用父作用域,为什么还要怎么麻烦?
解答 :主要是为了创建一个可以复用的指令,隔离作用域可以不受外界作用域的影响而单独存在,这可以方便我们将这些指令在其他地方使用。
3 如何同时使用方法绑定与双向绑定,怎么写?
解答: 写法的话相当于把两种单独的代码拿过来合起来就好,写在一个scope里面,可以一起定义。
鸣谢
感谢大家观看
BY:聂义中