AngularJS控制器controller正确的通信的方法


Posted in Javascript onJanuary 25, 2016

AngularJS是一款非常强大的前端MVC框架,AngularJS中的controller是个函数,用来向视图的作用域($scope)添加额外的功能,我们用它来给作用域对象设置初始状态,并添加自定义行为。

当我们在创建新的控制器时,angularJS会帮我们生成并传递一个新的$scope对象给这个controller,在angularJS应用的中的任何一个部分,都有父级作用域的存在,顶级就是ng-app所在的层级,它的父级作用域就是$rootScope。

每个$scope的$root指向$rootScope, $cope.$parent指向父级作用域。

cotroller之间的通信本质上是当前的controller所在的$scope如何跟其他controller上的$scope进行通信。

通常有3中解决方式:

利用作用域继承的原理,子控制器访问父级控制器中的内容。 使用angularJS中的事件,也就是使用$on,$emit,$broadcast进行消息传递 使用angularJS中的服务
第一种方式

即作用域嵌套作用域,有一定的使用限制,需要作用域嵌套起来,在实际开发中这种场景相对比较少,但也不是没有,这种方式更简单直接。

angularJS中默认情况下,当前作用域中无法找到某个属性时,就会在父级作用域中进行查找,若找不到直至查找到$rootScope。 如果在$rootScope中也无法找到程序依旧运行,但视图不会更新。

示例

javascript

//Javascript
app.controller('ParentController', function($scope) { 
$scope.person = {greeted: false};
});
app.controller('ChildController', function($scope) {
$scope.sayHello = function() {
$scope.person.name = 'Ari Lerner';
};
});
//HTML
<div ng-controller="ParentController">
<div ng-controller="ChildController">
<a ng-click="sayHello()">Say hello</a>
</div>
{{ person }}
</div>
//result
{"greeted":true, "name": "Ari Lerner"}

第二种方式

因为作用域是有层次的,所以可以利用作用域链传递事件。

传递事件有2种方式: * $broadcast: 触发的事件要通知整个事件系统(允许任意作用域处理这个事件)就要向下传播。 * $emit: 如果要提醒一个全局模块,需要通知更高层次的作用域时(例如$rootscope)需要把事件向上传递。

作用域上使用$on进行事件监听。

示例

JavaScript

app.controller('ParentController', function($scope) { 
$scope.$on('$fromSubControllerClick', function(e,data){
console.log(data); // hello
});
});
app.controller('ChildController', function($scope) {
$scope.sayHello = function() {
$scope.$emit('$fromSubControllerClick','hello');
};
});
//HTML
<div ng-controller="ParentController">
<div ng-controller="ChildController">
<a ng-click="sayHello()">Say hello</a>
</div>
</div>

在这里想要说的另外一个问题就是事件传播的性能问题,$broadcast+$on的方式回通知所有的子作用域,这里就会有性能问题,所以推荐使用$emit+$on的方式,为了进一步提升性能,定义的事件处理函数要在作用域销毁时一起释放掉。

使用$emit+$on的方式需要我们将事件监听绑定在$rootScope上,例如:

JavaScript

angular
.module('MyApp')
.controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {
var unbind = $rootScope.$on('someComponent.someCrazyEvent', function(){
console.log('foo');
});
$scope.$on('$destroy', unbind);
}
]);

但是这种方式有点繁琐,定义多个事件处理函数时整个人都不好了,所以我们来改进一下

利用装饰器来定义一个新的事件绑定函数:

JavaScript

angular
.module('MyApp')
.config(['$provide', function($provide){
$provide.decorator('$rootScope', ['$delegate', function($delegate){
Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
value: function(name, listener){
var unsubscribe = $delegate.$on(name, listener);
this.$on('$destroy', unsubscribe);
return unsubscribe;
},
enumerable: false
});
return $delegate;
}]);
}]);

那么我们在控制器中定义事件处理函数时:

JavaScript

angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);

个人强烈推荐此种做法

第三种方式

利用angularJS中service单例模式的特性,服务(service)提供了一种能在应用的整个生命周期内保持数据的方式,能够在控制器之间进行通信,且能保证数据的一致性。

一般我们都会封装server来为应用提供访问数据的接口,或者跟远程进行数据交互。

示例

JavaScript

var myApp = angular.module("myApp", []);
myApp.factory('Data', function() {
return {
name: "Ting"
}
});
myApp.controller('FirstCtrl', function($scope, Data) {
$scope.data = Data;
$scope.setName = function() {
Data.name = "Jack";
}
});
myApp.controller('SecondCtrl', function($scope, Data) {
$scope.data = Data;
$scope.setName = function() {
Data.name = "Moby";
}
});

以上所述是针对AngularJS控制器controller正确的通信的方法,希望能够帮助到大家。

Javascript 相关文章推荐
使两个iframe的高度与内容自适应,且相等
Nov 20 Javascript
javascript 嵌套的函数(作用域链)
Mar 15 Javascript
DOM Scripting中的图片切换[兼容Firefox]
Jun 12 Javascript
Jquery加载时从后台读取数据绑定到dropdownList实例
Jun 09 Javascript
JS实现点击下载的小例子
Jul 10 Javascript
简单的Jquery遮罩层代码实例
Nov 14 Javascript
jquery实现图片上传之前预览的方法
Jul 11 Javascript
js实现的动画导航菜单效果代码
Sep 10 Javascript
浅析js中substring和substr的方法
Nov 09 Javascript
Bootstrap栅格系统学习笔记
Nov 25 Javascript
从Vuex中取出数组赋值给新的数组,新数组push时报错的解决方法
Sep 18 Javascript
layui自定义工具栏的方法
Sep 19 Javascript
AngularJS入门心得之directive和controller通信过程
Jan 25 #Javascript
详解jquery事件delegate()的使用方法
Jan 25 #Javascript
AngularJS中的Directive实现延迟加载
Jan 25 #Javascript
AngularJS中的Directive自定义一个表格
Jan 25 #Javascript
理解JavaScript事件对象
Jan 25 #Javascript
AngularJS中如何使用$parse或$eval在运行时对Scope变量赋值
Jan 25 #Javascript
学习JavaScript事件流和事件处理程序
Jan 25 #Javascript
You might like
Zend的Registry机制的使用说明
2013/05/02 PHP
PHP加密技术的简单实现
2016/09/04 PHP
PHP开启目录引索+fancyindex漂亮目录浏览带搜索功能
2019/09/23 PHP
用Javscript实现表单复选框的全选功能
2007/05/25 Javascript
javascript textarea光标定位方法(兼容IE和FF)
2011/03/12 Javascript
jQuery中 noConflict() 方法使用
2013/04/25 Javascript
js实现拉伸拖动iframe的具体代码
2013/08/03 Javascript
javascript动态控制服务器控件实例
2014/09/05 Javascript
通过JS动态创建一个html DOM元素并显示
2014/10/15 Javascript
jQuery中[attribute=value]选择器用法实例
2014/12/31 Javascript
JS实现网页滚动条感应鼠标变色的方法
2015/02/26 Javascript
javascript中innerText和innerHTML属性用法实例分析
2015/05/13 Javascript
微信小程序 input输入框控件详解及实例(多种示例)
2016/12/14 Javascript
jQuery easyui datagird编辑行删除行功能的实现代码
2018/09/20 jQuery
webpack4.x CommonJS模块化浅析
2018/11/09 Javascript
nodejs同步调用获取mysql数据时遇到的大坑
2019/03/02 NodeJs
Node.js之删除文件夹(含递归删除)代码实例
2019/09/09 Javascript
python使用urllib模块开发的多线程豆瓣小站mp3下载器
2014/01/16 Python
Python中的FTP通信模块ftplib的用法整理
2016/07/08 Python
详解python中的 is 操作符
2017/12/26 Python
python+matplotlib绘制3D条形图实例代码
2018/01/17 Python
pycharm 将django中多个app放到同个文件夹apps的处理方法
2018/05/30 Python
在scrapy中使用phantomJS实现异步爬取的方法
2018/12/17 Python
Numpy中ndim、shape、dtype、astype的用法详解
2020/06/14 Python
python自动生成sql语句的脚本
2021/02/24 Python
优衣库台湾官网:UNIQLO台湾
2019/02/01 全球购物
世界领先的豪华床上用品供应商之一:Bedeck Home
2019/03/18 全球购物
Eclipse面试题
2014/03/22 面试题
2014年维稳工作总结
2014/11/18 职场文书
人事局接收函
2015/01/30 职场文书
2015年置业顾问工作总结
2015/04/07 职场文书
2015年秋季小学开学典礼主持词
2015/07/16 职场文书
幼儿园中班班级总结
2015/08/10 职场文书
银行培训心得体会范文
2016/01/09 职场文书
初一英语教学反思
2016/02/15 职场文书
ORACLE查看当前账号的相关信息
2021/06/18 Oracle