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 相关文章推荐
javascript 检测浏览器类型和版本的代码
Sep 15 Javascript
JavaScipt中的Math.ceil() 、Math.floor() 、Math.round() 三个函数的理解
Apr 29 Javascript
jquery ajax同步异步的执行最终解决方案
Apr 26 Javascript
单击复制文字兼容各浏览器的完美解决方案
Jul 04 Javascript
jQuery处理XML文件的几种方法
Jun 14 Javascript
浅谈Javascript中的Label语句
Dec 14 Javascript
详解node HTTP请求客户端 - Request
May 05 Javascript
Vue动态实现评分效果
May 24 Javascript
React复制到剪贴板的示例代码
Aug 22 Javascript
Vue-Cli 3.0 中配置高德地图的两种方式
Jun 19 Javascript
在vue项目中使用sass语法问题
Jul 18 Javascript
Vue实现省市区三级联动
Dec 27 Vue.js
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
PHP提取中文首字母
2008/04/09 PHP
PHP5.4中json_encode中文转码的变化小结
2013/01/30 PHP
php英文单词统计器
2016/06/23 PHP
PHP简单装饰器模式实现与用法示例
2017/06/22 PHP
如何判断图片地址是否失效
2007/02/02 Javascript
脚本安需导入(装载)的三种模式的对比
2007/06/24 Javascript
jquery实现手风琴效果实例代码
2013/11/15 Javascript
javascript实现拖动元素交换位置
2015/11/29 Javascript
JavaScript兼容浏览器FF/IE技巧
2016/08/14 Javascript
原生JS实现匀速图片轮播动画
2016/10/18 Javascript
微信小程序 wxapp内容组件 progress详细介绍
2016/10/31 Javascript
详解vue2.0 transition 多个元素嵌套使用过渡
2017/06/19 Javascript
Vue Ajax跨域请求实例详解
2017/06/20 Javascript
vue中添加mp3音频文件的方法
2018/03/02 Javascript
Vue 中axios配置实例详解
2018/07/27 Javascript
layui table设置前台过滤转义等方法
2018/08/17 Javascript
layui按条件隐藏表格列的实例
2019/09/19 Javascript
vue实现页面内容禁止选中功能,仅输入框和文本域可选
2019/11/09 Javascript
小程序外卖订单界面的示例代码
2019/12/30 Javascript
Python 正则表达式操作指南
2009/05/04 Python
Python进阶学习之特殊方法实例详析
2017/12/01 Python
Python中的上下文管理器和with语句的使用
2018/04/17 Python
详谈Python中列表list,元祖tuple和numpy中的array区别
2018/04/18 Python
解决每次打开pycharm直接进入项目的问题
2018/10/28 Python
Python MongoDB 插入数据时已存在则不执行,不存在则插入的解决方法
2019/09/24 Python
Pycharm中安装Pygal并使用Pygal模拟掷骰子(推荐)
2020/04/08 Python
pygame用blit()实现动画效果的示例代码
2020/05/28 Python
浅谈django channels 路由误导
2020/05/28 Python
浅谈opencv自动光学检测、目标分割和检测(连通区域和findContours)
2020/06/04 Python
加拿大品牌鞋包连锁店:Little Burgundy
2021/02/28 全球购物
营销部内勤岗位职责
2014/04/30 职场文书
体育口号大全
2014/06/18 职场文书
学校安全生产月活动总结
2014/07/05 职场文书
北京英语导游词
2015/02/12 职场文书
分布式锁为什么要选择Zookeeper而不是Redis?看完这篇你就明白了
2021/05/21 Redis
教你使用RustDesk 搭建一个自己的远程桌面中继服务器
2022/08/14 Servers