一招制敌 - 玩转 AngularJS 指令的 Scope (作用域),讲得特别好
学习了AngularJS挺长时间,最近再次回首看看指令这部分的时候,觉得比自己刚开始学习的时候理解的更加深入了,尤其是指令的作用域这部分。
步入正题:
每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部的Controller提供的作用域或者根作用域($rootScope)),还是创建一个新的自己的作用域,当然AngularJS为我们指令的
scope
参数提供了三种选择,分别是:false
,true
,{}
;默认情况下是false
。
scope = false
首先我们来看一下,当scope
参数被设置为false
时有什么情况发生
在这种情况下,在指令模板中可以直接使用父作用域中的变量,函数
首先我们来创建一个指令,代码如下所示:
JS代码:
angular.module("MyApp", [])
.controller("MyController", function ($scope) {
//J1 这里我们在作用域里初始化两个变量
$scope.name = "dreamapple";
$scope.age = 20;
//J2 创建一个方法,修改我们创建的对象的年龄
$scope.changeAge = function () {
$scope.age = 22;
}
})
//J3 创建我们的指令,指令名字为"myDirective"
.directive("myDirective", function () {
var obj = {
//J4 指令的声明模式为 "AE" 属性和元素
restrict: "AE",
//J5 指令继承父作用域的属性和方法
scope: false,
replace: true,
template: "<div class='my-directive'>" +
"<h3>下面部分是我们创建的指令生成的</h3>" +
"我的名字是:<span ng-bind='name'></span><br/>" +
"我的年龄是:<span ng-bind='age'></span>" +
"<input type='text' ng-model='name'>"+
" </div>"
}
return obj;
});
HTML代码:
<div ng-app="MyApp">
<div class="container" ng-controller="MyController">
<div class="my-info">我的名字是:<span ng-bind="name"></span>
<!-- 使用"ng-bind"防止网络状态不佳时出现没有被赋值表达式 -->
<br/>我的年龄是:<span ng-bind="age"></span>
</div>
<!-- 使用属性声明指令 -->
<div class="my-directive" my-directive></div>
</div>
</div>
CSS代码:
div{
padding: 6px;
}
div.container {
border: 1px solid black;
}
div.my-info {
border: 1px solid blue;
}
div.my-directive{
border: 1px solid green;
}
下面我们来详细解释一下上面的代码:
因为我们将
scope
的属性设置为false
所以,我们创建的指令继承了父作用域的一切属性和方法,这也使得在指令的模板中我们可以使用这些属性和方法。
注意:此时我们在输入框里改变名字,会发现上面的两个名字都发生了变化,你肯定会说,这肯定是这样啊,数据绑定嘛,好,我们接着往下走。
scope = true
当把scope
属性设置为true
时,这表明我们创建的指令要创建一个新的作用域,这个作用域继承自我们的父作用域。
等等,刚才我们不是说了,当把scope
属性值设置为false
时,不也是继承我们的父作用域吗?表急,我们接着往下看。
修改上面的JS代码,将指令中的:
scope:false
修改为scope:true
然后我们再试着在我们的input
输入框中写一些字符串,会发现,指令中的那个name
发生了变化,但是指令外的那个name
却没有发生变化,这说明了一个问题。
- 当我们将
scope
设置为true
的时候,我们就新创建了一个作用域,只不过这个作用域是继承了我们的父作用域;我觉得可以这样理解,我们新创建的作用域是一个新的作用域,只不过在初始化的时候,用了父作用域的属性和方法去填充我们这个新的作用域。它和父作用域不是同一个作用域。- 当我们将
scope
设置为false
的时候,我们创建的指令和父作用域(其实是同一个作用域)共享同一个model
模型,所以在指令中修改模型数据,它会反映到父作用域的模型中。
scope = {}
下面我们要进入一个好玩的部分,当我们将scope
的属性设置为{}
时,我们可以做更多的事情。
AngularJS最强的大的地方之一就是它可以构建组建,无论放在哪里都是可以使用的;
这所以可以做到这些,不得不归功于指令的这个属性;当我们将scope
设置为{}
时,意味着我们创建的一个新的与父作用域隔离的新的作用域,这使我们在不知道外部环境的情况下,就可以正常工作,不依赖外部环境。
当然首先我们还是要给出我们的例子,先看代码,我们修改了上述的JS代码和HTML代码
JS代码:
angular.module("MyApp", [])
.controller("MyController", function ($scope) {
$scope.name = "dreamapple";
$scope.age = 20;
$scope.changeAge = function(){
$scope.age = 0;
}
})
.directive("myDirective", function () {
var obj = {
restrict: "AE",
scope: {
name: '@myName',
age: '=',
changeAge: '&changeMyAge'
},
replace: true,
template: "<div class='my-directive'>" +
"<h3>下面部分是我们创建的指令生成的</h3>" +
"我的名字是:<span ng-bind='name'></span><br/>" +
"我的年龄是:<span ng-bind='age'></span><br/>" +
"在这里修改名字:<input type='text' ng-model='name'><br/>" +
"<button ng-click='changeAge()'>修改年龄</button>" +
" </div>"
}
return obj;
});
HTML代码:
<div ng-app="MyApp">
<div class="container" ng-controller="MyController">
<div class="my-info">我的名字是:<span ng-bind="name"></span>
<br/>我的年龄是:<span ng-bind="age"></span>
<br />
</div>
<div class="my-directive" my-directive my-name="{{name}}" age="age" change-my-age="changeAge()"></div>
</div>
</div>
我们使用了隔离的作用域,不代表我们不可以使用父作用域的属性和方法。
- 我们可以通过向
scope
的{}
中传入特殊的前缀标识符(即prefix
),来进行数据的绑定。 - 在创建了隔离的作用域,我们可以通过
@
,&
,=
引用应用指令的元素的属性,如上面的代码那样,我们可以在<div class="my-directive" my-directive my-name="{{name}}" age="age" change-my-age="changeAge()"></div>
这个元素中,利用前缀标识符通过使用属性my-name
,age
,change-my-age
来引用这些属性的值。
下面我们来看看如何使用这些前缀标识符:
@
这是一个单项绑定的前缀标识符
使用方法:在元素中使用属性,好比这样<div my-directive my-name="{{name}}"></div>
,注意,属性的名字要用-
将两个单词连接,因为是数据的单项绑定所以要通过使用{{}}
来绑定数据。
=
这是一个双向数据绑定前缀标识符
使用方法:在元素中使用属性,好比这样<div my-directive age="age"></div>
,注意,数据的双向绑定要通过=
前缀标识符实现,所以不可以使用{{}}
。
&
这是一个绑定函数方法的前缀标识符
使用方法:在元素中使用属性,好比这样<div my-directive change-my-age="changeAge()"></div>
,注意,属性的名字要用-
将多个个单词连接。
注意:在新创建指令的作用域对象中,使用属性的名字进行绑定时,要使用驼峰命名标准,比如下面的代码。
scope: {
// `myName` 就是原来元素中的`my-name`属性
name: '@myName',
age: '=',
// `changeMyAge`就是原来元素中的`change-my-age`属性
changeAge: '&changeMyAge'
}
进一步说明,我们的指令是如何利用这些前缀标识符来寻找我们想要的属性或者函数的?
@
当指令编译到模板的name
时,就会到scope
中寻找是否含有name
的键值对,如果存在,就像上面那样,看到@
就知道这是一个单向的数据绑定,然后寻找原来的那个使用指令的元素上(或者是指令元素本身)含有这个值的属性即my-name={{name}}
,然后在父作用域查找{{name}}
的值,得到之后传递给模板中的name
。=
和&
与@
差不多,只不过=
进行的是双向的数据绑定,不论模板还是父作用域上的属性的值发生改变都会使另一个值发生改变,而&
是绑定函数而已。
到这里我们关于AngularJS指令的作用域估计也理解的差不多了!
一招制敌 - 玩转 AngularJS 指令的 Scope (作用域),讲得特别好的更多相关文章
- AngularJS 指令的 Scope (作用域)
参考:https://segmentfault.com/a/1190000002773689 每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部的Controller提供的 ...
- angularJs指令的Scope(作用域)
每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部的Controller提供的作用域或者根作用域($rootScope)),还是创建一个新的自己的作用域,当然Angular ...
- angularjs指令中scope参数 true、false、{} 的区别详解
scope 有三个参数 true.false.{} scope 默认是 false,当 scope设置为true时,会从父作用域继承并创建一个新的作用域对象, 按照true .false的反向思维,我 ...
- angularJS MVC及$scope作用域
- AngularJS指令
1. AngularJS指令的特点: AngularJS通过被称为指令的新属性来扩展HTML,指令的前缀为ng-. AngularJS通过内置的指令来为应用添加功能. AngularJS允许你自定义指 ...
- 关于angularjs指令
一个指令用来引入新的HTML语法.指令是DOM元素上的标记,使元素拥有特定的行为.举例来说,静态的HTML不知道如何来创建和展现一个日期选择器控件.让HTML能识别这个语法,我们需要使用指令.指令通过 ...
- angularjs指令参数transclude
angularjs指令参数transclude transclude翻译为嵌入,和之前看到的vue中的slots作用差不多,目的是将指令元素的子内容嵌入到指令的模板中 定义指令 <div sid ...
- AngularJS中Directive指令系列 - scope属性的使用
文章是转的,我做下补充.原文地址:https://segmentfault.com/a/1190000002773689 每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部 ...
- angularjs 指令—— 绑定策略(@、=、&)
angularjs 指令—— 绑定策略(@.=.&) 引入主题背景:angular 的指令配置中的template可以直接使用硬编码写相应的代码,不过也可以根据变量,进行动态更新.那么需要用到 ...
随机推荐
- Effective Java 第三版——78. 同步访问共享的可变数据
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- 整体C#与Sql培训内容及结构
图如果看不清可以右键存图片到本地
- VMVare 虚拟机使用桥接模式
VMVare 虚拟机使用桥接模式,和物理机使用同一个物理网卡,和物理主机使用同一个段的ip. 1.VMware 编辑 > 虚拟网络编辑器 2.更改配置 3.编辑名称为VMnet0 的网络(如果 ...
- 浅析LRC歌词文件
[时间:2018-12] [状态:Open] [关键词:字幕,LRC,歌词,lyric,文件格式] 0 引言 几年前(2010年左右),网络音乐流行与免费的时代,网上有大量的mp3,使用比较常见的播放 ...
- find ctime 加减n时间范围
看下atime的时间解释:-atime n File was last accessed n*24 hours ago. When find figures out how many 24-hour ...
- 聊天机器人(chatbot)终极指南:自然语言处理(NLP)和深度机器学习(Deep Machine Learning)
在过去的几个月中,我一直在收集自然语言处理(NLP)以及如何将NLP和深度学习(Deep Learning)应用到聊天机器人(Chatbots)方面的最好的资料. 时不时地我会发现一个出色的资源,因此 ...
- 恒生UFX接口引用计数心得
本文介绍在基于恒生T2SDK基础上开发对接UFX柜台时,有关引用计数的一些心得体会. 下面以配置接口和连接接口为例子来介绍,下面是文档介绍: 创建配置接口说明: 3.1.2 创建配置接口(NewCon ...
- Python类和实例方法和属性的动态绑定
python中实例创建后可以给实例绑定任何属性和方法 class Student(object): pass 给实例绑定一个属性: s=Student() s.name='Michel' print ...
- 【Dubbo 源码解析】05_Dubbo 服务发现&引用
Dubbo 服务发现&引用 Dubbo 引用的服务消费者最终会构造成一个 Spring 的 Bean,具体是通过 ReferenceBean 来实现的.它是一个 FactoryBean,所有的 ...
- IP地址在mysql的存储(IP地址和int的转换)
PHP echo ip2long('192.168.1.38'); 输出:3232235814 MYSQL SELECT INET_ATON('192.168.1.38'); 输出:323223581 ...