什么是作用域:作用域是视图和控制器之间的胶水。
什么是控制器:每一个控制器都会从父级作用域通过原型继承的形式形成一个自己的作用域。控制器主要提供可以在指令间复用的行为。常常被用来放置多个指令之间的共享动作。
什么是指令:指令在特定DOM结构上运行的函数,指令可以拓展这个元素的功能。
控制器之间的通信:
注意:这里举出的例子是一些概念上的例子,表示这样做的可以的,但是真正运用到项目中的方法有些却不是这样,我稍后会说明。
一下这些转自:http://blog.csdn.net/yy374864125/article/details/39288931,亲自测试都是可以实现的。
1, 利用作用域的继承方式
由于作用域的继承是基于js的原型继承方式,所以这里分为两种情况,当作用域上面的值为基本类型的时候,修改父作用域上面的值会 影响到子作用域,反之,修改子作用域只会影响子作用域的值,不会影响父作用域上面的值;如果需要父作用域与子作用域共享一个值 的话,就需要用到后面一种,即作用域上的值为对象,任何一方的修改都能影响另一方,这是因为在js中对象都是引用类型。
基本类型
function Sandcrawler($scope) {
$scope.location = "Mos Eisley North";
$scope.move = function(newLocation) {
$scope.location = newLocation;
}
}
function Droid($scope) {
$scope.sell = function(newLocation) {
$scope.location = newLocation;
}
}
// html
<div ng-controller="Sandcrawler">
<p>Location: {{location}}</p>
<button ng-click="move('Mos Eisley South')">Move</button>
<div ng-controller="Droid">
<p>Location: {{location}}</p>
<button ng-click="sell('Owen Farm')">Sell</button>
</div>
</div>
对象
function Sandcrawler($scope) {
$scope.obj = {location:"Mos Eisley North"};
}
function Droid($scope) {
$scope.summon = function(newLocation) {
$scope.obj.location = newLocation;
}
}
// html
<div ng-controller="Sandcrawler">
<p>Sandcrawler Location: {{location}}</p>
<div ng-controller="Droid">
<button ng-click="summon('Owen Farm')">
Summon Sandcrawler
</button>
</div>
</div>
2, 基于事件的方式
在一般情况下基于继承的方式已经足够满足大部分情况了,但是这种方式没有实现兄弟控制器之间的通信方式,所以引出了事件的方式 。基于事件的方式中我们可以里面作用的$on,$emit,$boardcast这几个方式来实现,其中$on表示事件监听,$emit表示向父级以上的 作用域触发事件, $boardcast表示向子级以下的作用域广播事件。参照以下代码:
向上传播事件
function Sandcrawler($scope) {
$scope.location = "Mos Eisley North";
$scope.$on('summon', function(e, newLocation) {
$scope.location = newLocation;
});
}
function Droid($scope) {
$scope.location = "Owen Farm";
$scope.summon = function() {
$scope.$emit('summon', $scope.location);
}
}
// html
<div ng-controller="Sandcrawler">
<p>Sandcrawler Location: {{location}}</p>
<div ng-controller="Droid">
<p>Droid Location: {{location}}</p>
<button ng-click="summon()">Summon Sandcrawler</button>
</div>
</div>
向下广播事件
function Sandcrawler($scope) {
$scope.location = "Mos Eisley North";
$scope.recall = function() {
$scope.$broadcast('recall', $scope.location);
}
}
function Droid($scope) {
$scope.location = "Owen Farm";
$scope.$on('recall', function(e, newLocation) {
$scope.location = newLocation;
});
}
//html
<div ng-controller="Sandcrawler">
<p>Sandcrawler Location: {{location}}</p>
<button ng-click="recall()">Recall Droids</button>
<div ng-controller="Droid">
<p>Droid Location: {{location}}</p>
</div>
</div>
从这个用法我们可以引申出一种用于兄弟控制间进行通信的方法,首先我们一个兄弟控制中向父作用域触发一个事件,然后在父作用域 中监听事件,再广播给子作用域,这样通过事件携带的参数,实现了数据经过父作用域,在兄弟作用域之间传播。这里要注意的是,通过父元素作为中介进行传递的话,兄弟元素用的事件名不能一样,否则会进入死循环。请看代码:
兄弟作用域之间传播
function Sandcrawler($scope) {
$scope.$on('requestDroidRecall', function(e) {
$scope.$broadcast('executeDroidRecall');
});
}
function Droid($scope) {
$scope.location = "Owen Farm";
$scope.recallAllDroids = function() {
$scope.$emit('requestDroidRecall');
}
$scope.$on('executeDroidRecall', function() {
$scope.location = "Sandcrawler"
});
}
// html
<div ng-controller="Sandcrawler">
<div ng-controller="Droid">
<h2>R2-D2</h2>
<p>Droid Location: {{location}}</p>
<button ng-click="recallAddDroids()">Recall All Droids</button>
</div>
<div ng-controller="Droid">
<h2>C-3PO</h2>
<p>Droid Location: {{status}}</p>
<button ng-click="recallAddDroids()">Recall All Droids</button>
</div>
</div>
3, angular服务的方式
在ng中服务是一个单例,所以在服务中生成一个对象,该对象就可以利用依赖注入的方式在所有的控制器中共享。参照以下例子,在一个控制器修改了服务对象的值,在另一个控制器中获取到修改后的值:
var app = angular.module('myApp', []);
app.factory('instance', function(){
return {};
});
app.controller('MainCtrl', function($scope, instance) {
$scope.change = function() {
instance.name = $scope.test;
};
});
app.controller('sideCtrl', function($scope, instance) {
$scope.add = function() {
$scope.name = instance.name;
};
});
//html
<div ng-controller="MainCtrl">
<input type="text" ng-model="test" />
<div ng-click="change()">click me</div>
</div>
<div ng-controller="sideCtrl">
<div ng-click="add()">my name {{name}}</div>
</div>
那么,真正运用的项目中该是什么样子呢?
我目前认为有两点。1.控制器并不适合用来执行DOM操作、格式化或数据操作,以及除存储数据模型之外的状态维护操作。它只是视图和$scope之间的桥梁。。2是放置多个指令之间的共享动作。
他只是视图和scope之间的桥梁。控制器应该尽可能保持短小精悍,而在控制器中进行DOM操作和数据操作则是一个不好的实践。
设计良好的应用会将复杂的逻辑放到指令和服务中。通过使用指令和服务,我们可以将控制
器重构成一个轻量且更易维护的形式:
指令间的通信:
首先介绍一下指令的作用域
1.当scope:false(默认),此时该指令没有自身的作用域,他的作用域就是他的父级作用域,当指令中的scope的属性和他的父级scope的属性一样是,会相互影响,这肯定是我们不愿意看到的,再大型项目中,会有发生各种各样的问题。
2.当scope:true,此时该指令会从其父级作用域通过原型继承的形式生成一个自己的作用域。当scope的值一样是,也不会影响。
3.当scope:{},此时该指令会生成一个孤立作用域,这个scope只能在指令的方法中或者指令模板字符串中使用。
指令与控制器间的通信
一下这些转自:http://www.cnblogs.com/bigdataZJ/p/AngularJS1.html
粗略地翻了一遍《JavaScript DOM编程艺术》,就以为可以接过AngularJS的一招半式,一个星期过去了,我发现自己还是Too Young,Too Simple!(刚打照面的时候,我就被乱棍砸晕了-_-!)
1.AngularJS是何方神圣
Angular JS (Angular.JS) 是一组用来开发Web页面的框架、模板以及数据绑定和丰富UI组件。它支持整个开发进程,提供web应用的架构,无需进行手工DOM操作。
AngularJS是为了克服HTML在构建应用上的不足而设计的。HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了。这里AngularJS就应运而生,弥补了HTML的天然缺陷,用于构件Web应用等。
2.如何了解AngularJS
AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。
AngularJS官网 : http://www.angularjs.org (一般来说会被墙掉,所以可以访问下面的网站)
AngularJS中文网站 : http://www.ngnice.com
书籍 :《AngularJS 权威教程》《用AngularJS开发下一代Web应用》等。个人意见,For your information
备注 :视频教程,最近有看过大漠老师的AngularJS教程,觉得还不错,但是感觉没有一点基础还是听不懂的,或者要看好几遍(不是做广告)
3.为什么要了解AngularJS
一项新技术能够面世,为众人所知,从而脱引而出,定然不是空穴来风,肯定有其标新立异的过人之处,主要有以下几点:
(1)MVC的思想(或者是MVVM)
(2)模块化和依赖注入
(3)双向数据绑定
(4)指令
每一个特性都可以大篇幅的展开,显然,目前能力不够,没法展开,有兴趣可以网上搜下,大体了解。
今天主要来说说AngularJS的三个指令“ @ ”,“ = ”,“ & ”的用法和区别(这个问题困扰了我大半天,和Frank交流多次,我才明白)
1.指令作用域中的@
作用是把当前属性作为字符串传递。
先上代码,前台界面:
1 <!doctype html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 <link rel="stylesheet" href="../css/bootstrap.css"> 6 </head> 7 <body> 8 <div ng-controller="MyCtrl"> 9 <drink water="{{pureWater}}"></drink> 10 </div> 11 </body> 12 <script src="../js/angular.js"> 13 <script src="ScopeAt.js"></script> 14 </html>
JS代码:
1 var myModule = angular.module("MyModule", []); 2 myModule.controller('MyCtrl', ['$scope', function($scope){ 3 $scope.pureWater="纯净水"; 4 }]) 5 myModule.directive("drink", function() { 6 return { 7 restrict:'AE', 8 scope:{ 9 water:'@' 10 }, 11 template:"<div>{{water}}</div>" 12 } 13 });
执行的结果平淡无奇,却暗藏玄机:
(1) HTML页面中,声明一个标签<drink></drink>,其中定义一个属性名:water 属性值:pureWater(这里的{{}}是angularjs的一种常见表达式,类似于ng-model,用于值绑定)
(2) JS文件中,首先从模块开始,然后创建一个控制器行2~行4,再定义一个指令,主要实现的是将"<drink></drink>"替换为"<div>{{water}}</div>"标签显示
(3) 重点介绍这里的
scope:{ water:'@' }
该表达式等价于:
link:function(scope,element,attrs){ scope.water=attrs.water; }
具体含义就是在指令的scope上定义一个属性名:water,它的值就是前台界面中water属性的值,也就是"{{pureWater}}";
同时{{pureWater}}的值我们从声明的控制器可以看出:
$scope.pureWater="纯净水";
所以最终页面显示的是“纯净水”,主要的流程就是:
a.在指令中,通过@实现指令与HTML页面元素关联;
b.在控制器中又实现了与页面的联系;
c.从而借助HTML页面建立起控制器与指令的联系,也是一种通讯方式。
具体见下图:
2.指令作用域中的=
作用是与父scope中的属性进行双向绑定。
1 <!doctype html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 <link rel="stylesheet" href="../css/bootstrap.css"> 6 </head> 7 <body> 8 <div ng-controller="MyCtrl"> 9 Ctrl: 10 <br> 11 <input type="text" ng-model="pureWater"> 12 <br> 13 Directive: 14 <br> 15 <drink water="pureWater"></drink> 16 </div> 17 </body> 18 <script src="../js/angular.js"></script> 19 <script src="ScopeEqual.js"></script> 20 </html>
1 var myModule = angular.module("MyModule", []); 2 myModule.controller('MyCtrl', ['$scope', function($scope){ 3 $scope.pureWater="纯净水"; 4 }]) 5 myModule.directive("drink", function() { 6 return { 7 restrict:'AE', 8 scope:{ 9 water:'=' 10 }, 11 template:'<input type="text" ng-model="water"/>' 12 } 13 });
这里=的手段类似,通过页面设置两个输入框,分别代表指令和控制器的作用域,在JS代码实现了双向绑定,做到了控制器与指令在各自作用域内能够影响对方,也就是双向通信,具体思路与@类似,不赘述,上图:
3.指令作用域中的&
主要作用是传递一个来自父scope的函数,稍后调用。
1 <!doctype html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 <link rel="stylesheet" href="../css/bootstrap.css"> 6 </head> 7 <body> 8 <div ng-controller="MyCtrl"> 9 <greeting greet="sayHello(name)"></greeting> 10 <greeting greet="sayHello(name)"></greeting> 11 <greeting greet="sayHello(name)"></greeting> 12 </div> 13 </body> 14 <script src="../js/angular.js"></script> 15 <script src="ScopeAnd.js"></script> 16 </html>
1 var myModule = angular.module("MyModule", []); 2 myModule.controller('MyCtrl', ['$scope', function($scope){ 3 $scope.sayHello=function(name){ 4 alert("Hello "+name); 5 } 6 }]) 7 myModule.directive("greeting", function() { 8 return { 9 restrict:'AE', 10 scope:{ 11 greet:'&' 12 }, 13 template:'<input type="text" ng-model="userName" /><br/>'+ 14 '<button class="btn btn-default" ng-click="greet({name:userName})">Greeting</button><br/>' 15 } 16 });
从页面可以看出,这里定义了一个标签<greeting></greeting>,并在其中定义了属性名greet,与上面的@以及=不同的是,属性名后面是一个方法,所以,这里的&主要用于在Controller和directive之间传递函数,实现两者之间的函数通信,在JS中,将前台的greeting标签替换为template中的内容,一个输入框加上一个按钮,按钮上绑定了greet函数,与前台页面的greet相呼应,而前台的greet函数在控制器中有定义,所以指令中也是调用的控制器中的greet函数。执行结果如下:
(1)初始界面
(2)在第一个文本框填值
(2)在第二个文本框填值
(3)在第三个文本框填值