AngularJS.directive系列:嵌套directive的通讯及scope研究
一、directive中的scope
directive无疑是AngularJS中比较复杂难懂的部分,而directive中个scope更是其中最复杂的部分了,尤其是在嵌套directive中互相通讯的时候。
单独的directive中,scope概念还是比较简单的,此时scope的三种取值情况为:
- scope:false 此时,directive没有独立的scope对象,link函数中引用的scope对象来自于当前节点的默认controller
- scope:true 此时,directive拥有独立的scope对象,此scope是由父scope对象继承而来,可以访问父scope中的所有属性,此时实际上是通过继承链接(prototype链)访问的父scope中的属性,要注意的是,当给此scope继承而来的属性名称赋值的时候,子scope中会相应建立一个本地属性,此时改变的是本scope的变量属性,父scope中的属性是不会改变的。
- scope:{propertyName:"=@propertyValue"} 此时,directive中拥有一隔离的scope对象,其实就是一个全新的scope对象,和上面取值为true时的区别就是不能访问父scope中的属性,当然还是可以通过$parent属性去访问父scope对象中属性的。
当情况改变到嵌套directive中的子(或者说内部)directive中时,内部的directive的scope和我们的理解或习惯性的的认知有所不同,而造成这一切的原因是,AngularJS中其实根本没有嵌套directive一说!只要我们脑子里还把内部的directive当成独立的directive来看待就会明白了。比如我们要实现如下的嵌套directive:
<div my-grid height="500" width="300">
<div my-grid-row height="300">
<div my-grid-cell width=".33">
</div>
<div my-grid-cell width=".34">
</div>
<div my-grid-cell width=".33">
</div>
</div>
<div my-grid-row height="200">
<div my-grid-cell width=".5">
</div>
<div my-grid-cell width=".5">
</div>
</div>
</div>
var $myd=angular.module("myDirectives",[]);
$myd.directive("myGrid",function(){
return{
restrict:"A",
scope:{height:"@height",width:"@width"},
link:function(scope,el,attrs){
}
};
});
$myd.directive("myGridRow",function(){
return{
restrict:"A",
scope:true,
link:function(scope,el,attrs){
}
};
});
$myd.directive("myGridCell",function(){
return{
restrict:"A",
scope:true,
link:function(scope,el,attrs){
}
};
});
开上面代码可知myGrid设置了隔离的scope,myGridRow和myGridCell申请了继承的独立scope,现在猜猜,myGridRow和myGridCell的scope.$parent是谁,是不是myGrid的scope?不知道又没有tx认为(注意下面是示意代码,不是真的如此引用myGridCell和myGridRow的scope)
myGridCell.scope.$parent=myGridRow.scope myGridRow.scope.$parent =myGrid.scope
如果你也和我以前一样这样认为,那么就大错特错了,实际上应该是这样的:
myGridCell.scope.$parent=myGridRow.scope.$parent=myGrid.scope.$parent
也就是说,这三级的directive的scope的父scope对象是一个人,也就是myGrid所在div元素的父元素或祖先元素节点上指定的ngController或者通过路由设置给出的controller。
如果myGridRow和myGridCell的scope设为false或是不设置呢,此时myGrid有独立scope而myGridRow和myGridCell都没有,因此分享myGrid父元素的controller的scope,也就是:
myGrid.scope.$parent=myGridRow.scope=myGridCell.scope
而如果myGridCell和myGridRow的scope也设置为隔离的scope({}),那么此时和第一种情况一样,三个directive的父scope对象也都是同一个对象:myGrid父元素的controller的scope。
二、嵌套directive的通讯
以上研究了嵌套directive下的scope,可以看到我们不可能通过访问父或子directive中scope方式进行通讯,那么我们究竟应该怎样在各级directive中通讯呢?我知道的有两种方式:
1,通过注入$rootScope,然后在$rootScope中调用$broadcast和$on,发送和响应事件,这显然不是好的设计。
2,通过注入父directive的controller。我们看文档知道,directive有一个require属性,这里明确说明require的是指定的directive的controller,此时link函数可以有第四个参数,就是这个controller。下面看示意代码。
var $myd=angular.module("myDirectives",[]);
$myd.directive("myGrid",function(){
return{
restrict:"A",
scope:{height:"@height",width:"@width"},
controller:function($scope){
$scope.getHeight=function(){
return $scope.height;
};
$scope.getWidth=function(){
return $scope.width;
};
},
link:function(scope,el,attrs){
scope.height=parseInt(scope.height);
$scope.width=parseInt(scope.width);
}
};
});
$myd.directive("myGridRow",function(){
return{
restrict:"A",
scope:true,
require:"^myGrid",
controller:function($scope){
$scope.getWidth=function(){
return $scope.pCtrl.getWidth();
}
},
link:function(scope,el,attrs,pCtrl){
scope.pCtrl = pCtrl;
scope.pHeight = pCtrl.getHeight();
scope.height=parseInt(attrs["height"]);
}
};
});
$myd.directive("myGridCell",function(){
return{
restrict:"A",
scope:true,
require:"^myGridRow",
link:function(scope,el,attrs,rowCtrl){
scope.widthRatio = parseFloat(attr["width"]);
scope.width=scope.widthRatio * rowCtrol.
}
};
});
由上面代码可见,父子directive通讯需要的两个要素:
- 父directive中声明controller函数,这和我们平时声明controller差不多,同样可以注入$scope,不同的是这里还可以注入$element,$attrs等,详细的请相关查阅资料。
- 子directive中添加require属性,内容就是父directive的名字,前面添加"^"是告诉AngularJS到上级的元素中查找父directive的controller,而不是在同元素中找。如果子directive可以脱离父directive单独用,还需要加上"?",以来通知AngularJS,不是必须的,此时link的第四参数有可能为空。
注意:上述代码只是示意代码,并不能真正工作,如果你使用上述代码将会发现link函数中并不能获取到真正的数值。这是因为例子中嵌套directive是从内到外的顺序来初始化的,子directive的link函数调用时,AngularJS只是初始化了父Directive对象的Controller对象,父directive的link函数并没有调用过,所以你只能取到空值。我的解决方法时子directive在父directive中注册回调函数,然后由父directive在适当的时候回调子directive的方法,或者注册后就由父directive来布局子directive的html元素,具体要看你的目标是什么来定了。
AngularJS.directive系列:嵌套directive的通讯及scope研究的更多相关文章
- AngularJS系统学习之Directive(指令)
本文转自https://www.w3ctech.com/topic/1612 原文作者: Nicolas Bevacqua 原文:AngularJS’ Internals In Depth, Part ...
- AngularJS入门心得1——directive和controller如何通信
粗略地翻了一遍<JavaScript DOM编程艺术>,就以为可以接过AngularJS的一招半式,一个星期过去了,我发现自己还是Too Young,Too Simple!(刚打照面的时候 ...
- Angular之指令Directive系列
项目筹备近期开启Angular学习,指令比较难理解所以记录备案,推荐Angualr实战学习视频大漠穷秋 Angular实战 一.指令directive概述 指令可以对元素绑定事件监听或者改变DOM结构 ...
- angularjs可交互的directive
angularjs可交互的directive http://jsfiddle.net/revolunet/s4gm6/ directive开发上手练手,以注释的方式说明 html <body n ...
- AngularJS路由系列(6)-- UI-Router的嵌套State
本系列探寻AngularJS的路由机制,在WebStorm下开发.本篇主要涉及UI-Route的嵌套State. 假设一个主视图上有两个部分视图,部分视图1和部分视图2,主视图对应着一个state,两 ...
- AngularJS创建新指令directive参数说明
var myapp = angular.module('myapp', []); myapp.directive('worldname', function() { return { template ...
- AngularJS路由系列(1)--基本路由配置
本系列探寻AngularJS的路由机制,在WebStorm下开发.主要包括: ● 路由的Big Picture ● $routeProvider配置路由 ● 使用template属性 ● 使用temp ...
- angularjs自动化测试系列之jasmine
angularjs自动化测试系列之jasmine jasmine参考 html <!DOCTYPE html> <html lang="en"> <h ...
- AngularJS路由系列(5)-- UI-Router的路由约束、Resolve属性、路由附加数据、路由进入退出事件
本系列探寻AngularJS的路由机制,在WebStorm下开发.主要包括: ● UI-Router约束路由参数● UI-Router的Resolve属性● UI-Router给路由附加数据● UI- ...
随机推荐
- mysql 锁表操作流程
- linux清理Java环境
1.清理Java环境rm -f /usr/bin/javarm -f /etc/alternatives/java rm -f /usr/bin/javacrm -f /etc/alternative ...
- oracle中for循环
DECLARE );-- 定义一个字符串变量str BEGIN .. loop -- INSERT INTO FW_TEST(NAME) VALUES('bbb' + i);DECODE('1','' ...
- [设备]Linux设备是否可以被多个进程或者线程同时Open?
当然可以 只要底层driver没有对重复打开做特殊处理,一般都可以被两个进程open 那当两个进程同时打开一个设备,当此设备收到数据时,怎么能保证每个进程都能收到数据?
- MSXML4 SP2 sp3安装时出错
没有启动Windows Module Installer 服务或者windows installer服务,重启试试 Windows Installer Cleanup Tool清理早期的在选项框中找到 ...
- 【整理】fiddler不能监听 localhost和 127.0.0.1的问题
localhost/127.0.0.1的请求不会通过任何代理发送,fiddler也就无法截获. 解决方案 1,用 http://localhost. (locahost紧跟一个点号)2,用 http: ...
- [转]css选择器优先级深入理解
转载自:http://www.jb51.net/css/67029.html 一.基础选择器 css基础选择器有标签选择器.类选择器.id选择器.通用选择器 1.标签选择器 每个html页面都由很多个 ...
- 数据框排序 data.frame order
# sorting examples using the mtcars datasetattach(mtcars) # sort by mpgnewdata <- mtcars[order(mp ...
- 关于Unity中水和雾的使用
水 自己来做水和雾还是有点麻烦的,不过没关系,Unity帮我们做好了很多可以用的. 1.Unity自己实现了水的特效,帮助我们解决游戏中水的问题 2.Unity的水集成在了Environment的环境 ...
- 3D Face Reconstruction
方法1 Large Pose 3D Face Reconstruction from a Single Image via Direct Volumetric CNN Regression http: ...