1. 指令简介
(1) 指令:自定义HTML元素和属性
[1] HTML引导
在HTML中要用内置指令ng-app标记出应用的根节点。这个指令需要以属性形式使用,可以写到任何位置,但是写到<html>
的开始标签上是最常规的做法。
<html ng-app='myApp'>
<!-- 应用的$rootScope -->
</html>
[2] 我们的第一个指令
下例创建了一个自定义指令。通过AngularJS模块API中的.directive()方法,通过传入一个字符串(指令名称)和一个函数(返回一个对象)来注册一个新指令。
注意:指令名称应用驼峰命名。
<my-directive></my-directive>
angular.module('myApp',[])
.directive('myDirective',function(){
return {
restrict: 'E',template: '<a href="https://baidu.com">Click me to go to Baidu</a>'
}
})
<my-directive>
<a href="https://baidu.com">Click me to go to Baidu</a>
</my-directive>
但是,我们并不想多增加一个节点,看到my-directive这样的标签,可以在创建是增加replace
属性。replace方法会用自定义元素取代指令声明,而不是嵌套在其内部。
angular.module('myApp',[])
.directive('myDirective',function(){
return {
restrict: 'E',replace: true,//----看这里
template: '<a href="https://baidu.com">Click me to go to Baidu</a>'
}
})
得到代码:
<a href="https://baidu.com">Click me to go to Baidu</a>
[3] 创建合法指令
下面都是创建指令的合法格式:
<my-directive></my-directive> <!--元素(E)-->
<div my-directive></div> <!--属性(A)-->
<div class='my-directive'></div> <!--类 (C)-->
<!-- directive:my-directive --> <!--注释(M)-->
主要在指令定义中的restrict设置。说明可以用哪种声明格式来匹配指令定义。
上例中,restrict: 'E'
,表明只能使用元素的方式。如果允许所有类型,可改为restrict: 'EACM'
,以此类推。
推荐使用属性方式,也就是A,因为有比较好的跨浏览器兼容性。特别对于IE浏览器。
[4] 表达式
<h1 ng-init="greeting='Hello World'"> The greeting is {{greeting}} </h1>
得到结果为:The greeting is Hello World
上例中,将表达式greeting='Hello World'
赋值给内置指令gn-init
。
(2) 向指令中传递数据
[1] 传递数据
上面go to baidu的那个例子中,如果不将URL和链接文本混在指令内部,可以提供更好的体验。所以,让其接受两个变量。
改为:
<div my-directive my-url='http://baidu.com' my-link-text='Click me to go to Baidu'><@H_690_403@/div>
template: '<a href="{{myUrl}}">{{myLinkText}}</a>'
运行结果并未生效。AngularJS允许通过创建新的子作用域或者隔离作用域来解决这个问题。
angular.module('myApp',function(){
return {
restrict: 'A',replace: true,scope:{
myUrl: '@',//----看这里,绑定策略
myLinkText: '@'//----看这里,绑定策略
},template: '<a href="{{myUrl}}">{{myLinkText}}</a>'
}
})
[2] 动态传递
创建一个文本输入域,将输入的值同指令内部隔离作用域的属性绑定起来。
这是书上的实现方式,使用了some-attr进行中转:
<label>Their URL field:</label>
<input type="text" ng-model="theirUrl">
<div my-directive
some-attr='theirUrl'
my-link-text='Click me to go to Baidu'></div>
angular.module('myApp',scope:{
myUrl: '=someAttr',//----看这里
myLinkText: '@'
},template: '<div><label>My URL field:</label><input type="text" ng-model="myUrl"><a href="{{myUrl}}">{{myLinkText}}</a></div>'
}
})
尝试不适用中转也是可以的:
<label>Their URL field:</label> <input type="text" ng-model="theirUrl"> <div my-directive my-url='{{theirUrl}}' my-link-text='Click me to go to Baidu'></div>
angular.module('myApp',myLinkText: '@'
},template: '<div><label>My URL field:</label><input type="text" ng-model="myUrl"><a href="{{myUrl}}">{{myLinkText}}</a></div>'
}
})
2. 内置指令
所有以ng前缀开头作为命名控件指令都是AngularJS提供的内置指令。因此,不要用ng作为自定义指令的命名前缀。
(1) 基础ng属性指令
以下是和原生HTML标签名称相似的内置指令,仅仅加了ng前缀。
ng-href
ng-src
ng-disabled
ng-checked
ng-readonly
ng-selected
ng-class
ng-style
[1] 布尔属性
根据HTML标准的定义,布尔属性代表一个true或者false值。当这个属性出现时,值就为true(无论实际定义的值是什么)。如果未出现,值为false。
1) ng-disabled
可以绑定到以下表单输入字段上:
<input>
<textarea>
<select>
<button>
<input type="text" ng-model="someProperty" placeholder="TypetoEnable">
<button ng-model='button' ng-disabled='!someProperty'>AButton</button>
2) ng-readonly
第一个文本框输入的时候,后一个文本框中的内容为只读。
<input type="text" ng-model="someProperty">
<input type="text" ng-readonly="someProperty" value="Some text here">
3) ng-checked
下例,通过ng-init
指令将someProperty的值设置为true,将someProperty和ng-checked
绑定在一起,这样默认把复选框勾选。点击取消勾选,someProperty的值也会跟着变化。
<label>someProperty={{someProperty}}</label> <input type="checkBox" ng-checked='someProperty' ng-init='someProperty=true' ng-model="someProperty">
4) ng-selected
下例,点选了checkBox后,select会自动切换到对应的option。
<label>Select Two Fish:</label>
<input type="checkBox" ng-model='isTwoFish'>
<select>
<option>One Fish</option>
<option ng-selected="isTwoFish">Two Fish</option>
</select>
[1] 类布尔属性
ng-href和ng-src虽不是标准的HTML布尔属性,但行为相似,在AngularJS内部是同等对待的。这两个属性能有效帮助重构和避免错误,强烈建议代替原来的href和src属性。
1) ng-href
当前作用域中的属性动态创建URL,应用ng-href代替href。
下例说明了使用href的潜在问题,用户点击时,若插值未生效,将会跳转到错误页面(IE会出现此种情况)。
<a ng-href="{{myHref}}">I'm felling lucky,when I load</a> <a href="{{myHref}}">I'm felling 404</a>
angular.module('myApp',[])
.run(function($rootScope,$timeout){
$timeout(function(){
$rootScope.myHref='http://baidu.com'
},2000);
});
2) ng-src
道理同上。
(2) 在指令中使用作用域
以下指令会以父级作用域为原型生成子作用域。这种继承的机制可以创建一个隔离层,用来将需要协同工作的方法和数据模型对象放置在一起。
ng-app和ng-controller是特殊的指令,因为会修改嵌套在他们内部的指令的作用域。
[1] ng-app
任何具有ng-app属性的DOM元素将被标记为$rootScope
的起始点。
<!doctype html> <html ng-app='myApp'> <head> <Meta charset="utf-8"> <Meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" /> <script src="/js/angular.min.js"></script> </head> <body> {{someProperty}} <button ng-click="someAction()">human button</button> </body> <script> angular.module('myApp',[]) .run(function($rootScope){ //只是演示,不建议这么用!!! $rootScope.someProperty='Hello computer'; $rootScope.someAction=function(){ $rootScope.someProperty='Hello human'; }; }); </script> </html>
[2] ng-controller
作用是为嵌套在其中的指令创建一个子作用域,避免所有操作和模型都定义在$rootScope
上。
将上例改造一下,将数据和操作放到子作用域中:
<div ng-controller='SomeController'> {{someModel.someProperty}} <button ng-click="someAction()">human button</button> </div>
angular.module('myApp',[])
.controller('SomeController',function($scope){
$scope.someModel={
someProperty:'Hello computer'
}
$scope.someAction=function(){
$scope.someModel.someProperty='Hello human';
};
});
使用子作用域意味着其上的数据模型和操作在应用的其他地方是无法访问的,只能被这个作用域内的指令和子作用域访问。显式声明数据模型非常重要。
下例中,进行了嵌套。由于原型的继承关系,修改父级对象中的someBareValue会同时修改子对象中的值,反之不行。这个例子充分说明子控制器是复制而非引用someBareValue。
<div ng-controller='SomeController'> {{someBareValue}} <button ng-click="someAction()">communicate to child</button> <div ng-controller='ChildController'> {{someBareValue}} <button ng-click="childAction()">communicate to parent</button> </div> </div>
angular.module('myApp',function($scope){
$scope.someBareValue='Hello computer';//错误示范
$scope.someAction=function(){
$scope.someBareValue='Hello human,from parent';
};
})
.controller('ChildController',function($scope){
$scope.childAction=function(){
$scope.someBareValue='Hello human,from child';
};
});
如果将模型对象的某个属性设置成对象,就会通过引用进行共享,在子$scope
中修改属性也会修改父$scope
中的这个属性。
<div ng-controller='SomeController'> {{someModel.someValue}} <button ng-click="someAction()">communicate to child</button> <div ng-controller='ChildController'> {{someModel.someValue}} <button ng-click="childAction()">communicate to parent</button> </div> </div>
angular.module('myApp',function($scope){
$scope.someModel={
someValue:'Hello computer' //正确示范
};
$scope.someAction=function(){
$scope.someModel.someValue='Hello human,function($scope){
$scope.childAction=function(){
$scope.someModel.someValue='Hello human,from child';
};
});
此时,不管先点击哪个按钮,值都会同步修改。
[3] ng-include
可以加载、编译并包含外部HTML片段到当前的应用中。
在同一个元素上添加onload属性可以在模板加载完成后执行一个表达式。
使用ng-include时,会自动创建一个子作用域。如果想使用某个特定作用域,需在同一个DOM元素上添加ng-controller指令。这样,当模板加载完成后,不会从外部作用域继承并创建一个新的子作用域。
<!--myTemplateName.html--> <p>Hello {{name}},I am been included</p>
<div ng-include="'myTemplateName.html'" ng-controller="MyController" ng-init="name='World'" onload="showGreeting()">
</div>
angular.module('myApp',[])
.controller('MyController',function($scope){
$scope.showGreeting=function(){
console.log($scope.name);
}
});
注意:ng-include中为一个字符串,双引号中还有单引号。
运行代码: Hello World,I am included,并在console里面打印出World。
[4] ng-switch
这个指令和ng-switch-when及on=”propertyName”一起使用,可以在propertyName发生变化时,渲染不同指令到视图中。
下例,当输入Ari时,文本显示Yes,it’s Ari,其余时候显示Guess the winner。
<input type="text" ng-model='person.name'> <div ng-switch on="person.name"> <p ng-switch-default>Guess the winner</p> <h1 ng-switch-when='Ari'>Yes,it's {{person.name}}</h1> </div>
[5] ng-view
用来设置将被路由管理和放置在HTML中的视图的位置。详见12章
[6] ng-if
和ng-show
/ng-hide
根据表达式的值(true或者false)在DOM中生成或移除一个元素。
ng-if
同ng-show
和ng-hide
的本质区别是,并非通过css显示或者隐藏某个节点,而是生成和移除。
<input type="checkBox" ng-model='insertElement'>
<span>Select to insert new element</span>
<h3 ng-if='insertElement'>I am inserted</h3>
[7] ng-repeat
用来遍历一个集合或为集合中的每个元素生成一个模板实例。集合中的每个元素都会被赋予自己的模板和作用域。同时,每个模板实例的作用域中都会暴露一些特殊的属性。
$index
: 遍历的进度(0…length-1)$first
: 当元素是遍历的是第一个时,值为true$middle
: 当元素处于非第一个和最后一个元素时,值为true$last
当元素是遍历的最后一个时,值为true$even
当$index
是偶数时,值为true$odd
当$index
是奇数时,值为true下例制作颜色相间的表格,由于索引是从0开始,所以使用
!$even
和!$odd
进行布尔值反转。
.odd{ background-color: wheat; }
.even{ background-color: grey; }
<ul ng-controller='PeopleController'> <li ng-repeat='person in people' ng-class="{even: !$even,odd: !$odd}"> {{person.name}} lives in {{person.city}} </li> </ul>
angular.module('myApp',[])
.controller('PeopleController',function($scope){
$scope.people=[
{name:'Ari',city:'San Francisco'},{name:'Amy',city:'Beijing'},{name:'Joyce',city:'New York'},{name:'Darren',city:'Chengdu'},{name:'Erik',city:'Seattle'}
]
});
[8] ng-init
用来在指令被调用时设置内部作用域的初始状态。
常见应用场景为需要创建小的示例代码时。对于需要健壮结构的场景,需在控制器中用数据模型对象来设置。
<div ng-init="greeting='Hello';person='World'"> {{greeting}} {{person}} </div>
[9] {{}}
和ng-bind
AngularJS内置的模板语法,它会在内部$scope
和视图之间创建绑定。只要$scope
发生变化,视图就会自动更新。
{{}}
是ng-bind
的简略形式。在屏幕可视区域使用会导致页面加载时未渲染元素发生闪烁,用ng-bind
可避免这个问题。
[10] ng-cloak
除了使用ng-bind
来避免未渲染元素闪烁,还可以在含有{{}}
的元素上使用ng-cloak
指令。
<div ng-init="greeting='Hello'"> <p ng-cloak>{{greeting}}</p> </div>
[11] ng-bind-template
同ng-bind
指令类似,ng-bind-template
用来在视图中绑定多个表达式。
<div ng-init="greeting='Hello';person='world'"> <p ng-bind-template="{{greeting}} {{person}}"></p> </div>
[12] ng-model
用来将input、select、text area或自定义表单控件同包含他们的作用域中的属性进行绑定。如果属性不存在,会隐式创建并添加到当前作用域。
<input type="text" ng-model='modelName.someProperty'> <p>{{modelName.someProperty}}</p>
[13] ng-change
会在表单输入发生变化时,计算给定表达式的值。需要和ng-model联合使用。
<div ng-controller="EquationController"> <input type="text" ng-model='equation.x' ng-change='change()'> + <input type="text" ng-model='equation.y' ng-change='change()'> = <code>{{equation.output}}</code> </div>
angular.module('myApp',[])
.controller('EquationController',function($scope){
$scope.equation={};
$scope.change=function(){
var x=$scope.equation.x?parseInt($scope.equation.x):0;
var y=$scope.equation.y?parseInt($scope.equation.y):0;
$scope.equation.output=x+y;
};
});
[14] ng-form
用来在一个表单内部嵌套另一个表单。
以下CSS类会根据表单的验证状态自动设置:
input.ng-invalid{ border: 1px solid red;}
input.ng-valid{ border: 1px solid green;}
<form name='signup_form' ng-controller="FormController" ng-submit='submitForm()' novalidate> <div ng-repeat='field in fields' ng-form='signup_form_input'> <input type="text" name='dynamic_input' ng-required="field.isrequired" ng-model='field.name' placeholder="{{field.placeholder}}"> <span class='error' ng-show='signup_form_input.dynamic_input.$error.required'>The field is required.</span> </div> <button type='submit' ng-disabled="signup_form.$invalid">submit</button> </form>
angular.module('myApp',[])
.controller('FormController',function($scope){
$scope.fields=[
{placeholder:'Uername',isrequired:true},{placeholder:'Password',{placeholder:'Email(optional)',isrequired:false}
];
$scope.submitForm=function(){
alert('it works');
};
});
[15] ng-click
<div ng-controller='CounterController'> <button ng-click='count = count + 1' ng-init="count=0">Increase</button> count: {{count}} <button ng-click="decrease()">Decrease</button> </div>
angular.module('myApp',[])
.controller('CounterController',function($scope){
$scope.decrease=function(){
$scope.count=$scope.count -1;
};
});
[16] ng-select
用来将数据同<select>
元素绑定。这个指令可以和ng-model
和ng-options
一同使用。
ng-options
的值是一个内涵表达式,可以接受一个数组或者对象,并对他们进行循环,将内部的内容提供给select标签内部的选项。
<div ng-controller='CityController'> <select ng-model='city' ng-options='city.name for city in cities'> <option value="">Choose City</option> </select> Best City: {{city.name}} </div>
angular.module('myApp',[])
.controller('CityController',function($scope){
$scope.cities=[
{name:'Seattle'},{name:'San Francisco'},{name:'Chicago'},{name:'New York'},]
});
[17] ng-submit
用来将表达式同onsubmit事件进行绑定。这个指令同时会阻止默认行为(发送请求并重新加载页面)。
<form ng-controller="FormController" ng-submit='submit()' > Enter text and hit enter: <input type="text" ng-model='person.name' name='person.name' /> <br> <code>people={{people}}</code> <ul ng-repeat="(index,object) in people"> <li>{{object.name}}</li> </ul> </form>
angular.module('myApp',function($scope){
$scope.person={
name: null
};
$scope.people=[];
$scope.submit=function(){
if($scope.person.name){
$scope.people.push({name: $scope.person.name});
$scope.person.name='';
}
};
});
[18] ng-class
动态设置元素的类,方法是绑定一个代表所有需要添加的类的表达式。当表达式发生变化,先前添加的类会被移除,新类会被添加。
下例,生成1-10的随机数,大于5时,显示红色的You won!
<div ng-controller="LotteryController"> <button ng-click="x=generateNumber()" ng-init="x=0">Draw Number</button> <div ng-class="{red: x>5}" ng-if="x> 5">You won!</div> <p>Number is: {{x}}</p> </div>
angular.module('myApp',[])
.controller('LotteryController',function($scope){
$scope.generateNumber=function(){
return Math.floor((Math.random()*10)+1);
};
});
[18] ng-attr-(suffix)
当AngularJS编译DOM时会查找花括号内的表达式,这些表达式会被自动注册到$watch
服务中并更新到$digest
循环中,成为它的一部分。
有时浏览器会对属性进行很苛刻的限制,如下例子:
<!--错误示例--> <svg ng-init="cx=100"> <circle cx="{{cx}}" cy="50" r="40" fill="wheat"/> </svg>
会报错,指出有一个非法属性。
可用ng-attr-cx
来解决:
<svg ng-init="cx=100"> <circle ng-attr-cx="{{cx}}" cy="50" r="40" fill="wheat"/> </svg>
3. 指令详解
(1) 指令定义
angular.module('myApp',[])
.directive('myDirective',function(){
//一个指令定义对象
return{
//通过设置项来定义指令,在这里进行覆写
}
}
定义一个指令可以使用的全部设置选项:
[1] restrict(字符串)
E(元素)、A(属性,默认值)、C(类名)、M(注释)
[2] priority(数值)
优先级参数可以设置为一个数值。默认值为0。
大多指令忽略该参数,但有些场景必须。例如,ng-repeat设置为1000,可以保证在同一元素上,总是在其他指令之前被调用。
[3] terminal(布尔型)
设置是否停止运行当前元素上比本指令优先级低的指令。
例如ng-view和ng-if。如果ng-if为true,ng-view正常执行;为false,ng-view(优先级较低)不执行。
[4] template(字符串或函数)
必须存在一个根DOM元素,每行末尾的反斜线,确保正确解析多行字符串。
实际开发中,最好使用templateUrl引用外部模板,因为多行文本维护难度大。
template:'\
<div><!--single root element-->\
<a>Click me</a>\
<p>Hello</p>\
</div>\
'
[5] templateUrl(字符串或函数)
默认情况下,会在后台通过Ajax来请求HMTL模板文件。模板加载是异步的,意味着编译和链接要暂停,等待模板加载完成。
[6] replace(布尔型)
可选参数,默认值为false。默认值意味着模板会被当做子元素插入到调用此指令的元素内部。
(2) 指令作用域
[1] scope(布尔型或对象)
可选参数,默认值为false。作用域的继承机制是向下而非向上的。
当scope设置为true时,会从父作用域继承并创建一个新的作用域对象。内置指令ng-controller就是这样的,创建一个新的从父作用域继承而来的子作用域。
<div ng-init="div1Property='div 1 property'"> Inside Div1:{{div2Property}} <div ng-init="div2Property='div 2 property'" ng-controller="div2Controller"> Inside Div2: {{div2Property}} <div ng-controller='dvi3Controller'> Inside Div3: {{div2Property}} <br> Inside Div3,Outside myDirective: {{directiveProperty}} <div my-directive ng-init="directiveProperty='directive property'"> Inside Div3,Inside myDirective: {{directiveProperty}} </div> </div> </div> </div>
angular.module('myApp',[])
.controller('div2Controller',function($scope){})
.controller('dvi3Controller',function($scope){})
.directive('myDirective',function(){
return{
restrict: 'A',scope: true //----看这里
}
})
从下图的结果中可以看出作用域的继承机制是向下,在div3中依旧可以访问div2中的属性,而在div1中却不行。
scope属性的区别体现在下图红框中。如果scope为true,意味着新建了一个作用域,所以在指令之外访问不到这个属性。而当scope为false的时候,指令在div3这个作用域中,所以在指令外依旧可以访问。
[2] 隔离作用域
隔离作用域的指令最主要的使用场景是创建可复用的组件,组件可以在未知上下文中使用,指令的模板无法访问外部作用域。
创建隔离作用域,设置scope为一个空对象{}。下表进行了对比:
scope的值 | 产生一个子作用域(作用域范围只有template) | 继承父作用域 |
---|---|---|
false | × | - |
true | √ | √ |
{} | √ | × |
<div ng-init="myProperty='wow,this is cool'">
surrounding scope: {{myProperty}}
<div my-directive-obj ></div>
<div my-directive-@H_962_3011@true ></div>
</div>
angular.module('myApp',[])
.directive('myDirectiveObj',scope: {},//----看这里
template:'<div>Inside myDirective({}): {{myProperty}}</div>'
}
})
.directive('myDirectiveTrue',scope: true,//----看这里
template:'<div>Inside myDirective(true): {{myProperty}}</div>'
}
})
运行结果为:
surrounding scope: wow,this is cool
Inside myDirective({}):
Inside myDirective(true): wow,this is cool
(3) 绑定策略
AngularJS提供了几种方法能够将指令内部的隔离作用域与外部作用域进行数据绑定,需要使用以下三种中的一种:
[1] @
把当前的属性作为字符串传递
<div ng-controller="MyController"> <div my-directive flavor="{{ctrlFlavor}}"></div> </div>
angular.module('myApp',function($scope){
$scope.ctrlFlavor="鸡尾酒";
})
.directive("myDirective",function(){
return{
restrict:'A',scope:{
flavor:'@' //自动绑定,传递的是字符串
},template:"<div>{{flavor}}</div>",};
});
运行结果为:鸡尾酒
指令中有一个flavor属性,其外层的div中的scope有一个ctrlFlavor属性,上面的例子实现外层div中scope的值绑定在指令的flavor属性上。
[2] =
与父scope中的属性进行双向绑定
<div ng-controller="MyController"> <p>{{ctrlFlavor}}</p> <div my-directive flavor="ctrlFlavor"></div> </div>
angular.module('myApp',scope:{
flavor:'=' //双向绑定
},template:'<input type="text" ng-model="flavor"/>',};
});
指令中的flavor属性是和外部作用域中的ctrlFlavor双向绑定的。指令中的值发生变化,作用域中的ctrlFlavor会跟着变化。
[3] &
传递来自父scope中的函数
<div ng-controller="MyController">
<div my-directive greet="sayHello(name)"></div>
<div my-directive greet="sayHello(name)"></div>
<div my-directive greet="sayHello(name)"></div>
</div>
angular.module('myApp',[])
.controller('MyController',function($scope){
$scope.sayHello=function(name){
alert('Hello,'+name);
};
})
.directive("myDirective",function(){
return{
restrict:'A',scope:{
greet:'&'
},template:'<input type="text" ng-model="userName" /><br/>'+
'<button ng-click="greet({name:userName})">问候一下</button><br/>'
};
});
在div中绑定一个Controller,这个Controller中定义了一个sayHello的方法,在div中又定义了一个名为myDirective的指令,这个指令的greet方法与父层scope的sayHello相互关联,父scope中的函数就传递到了子scope中。
[4] transclude(布尔型)
默认值为false。
关于这个属性,看文档根本没有看懂,并不理解为啥设置这个属性,以及与replace的区别。下面详细讲解如下:
首先,看下replace:
<hello>
<div>Hello everyone!</div>
</hello>
angular.module('myApp',[])
.directive("hello",function() {
return {
restrict:"AE",replace:true //---看这里
template:"<div>My name is Joyce</div>",}
});
运行结果为:My name is Joyce
我们发现,template里面的内容会彻底替代hello标签内的内容。这并不是希望的结果,因为这种方式完全无法完成标签的嵌套。于是,有了transclude。
在模板中添加了<div ng-transclude></div>
就是告诉ng把hello标签内部的内容全部放在ng-transclude所在的位置。
angular.module('myApp',[])
.directive("hello",function() {
return {
restrict:"AE",transclude: true,//---看这里
template:"<div ng-transclude></div><div>My name is Joyce</div>",}
});
运行结果为:
Hello everyone!
My name is Joyce
如下图,hello内部原来的DOM结构被这个ng-transclude指定的div包裹起来了,而且内部原来的DOM也被添加了一个内置的class,也就是ng-scope,这一点一定要注意!
[5] controller(字符串或函数)
angular.module('myApp',function() {
restrict: 'A',controller: 'SomeController'
})
当设置为函数时,在指令内部通过匿名构造函数来定义内联的控制器。
angular.module('myApp',function() {
restrict: 'A',controller:
function($scope,$element,$attrs,$transclude) {
// 控制器逻辑放在这里
}
});
1)$scope
与指令元素相关联的当前作用域
2)$element
当前指令对应的元素
3)$attrs
有当前元素的属性组成的对象,例如:
<div id='myDiv' class='container' my-directive ></div>
属性对象为:
{ id:'myDiv',class:'container' }
4)$transclude
嵌入链接函数会与对应的嵌入作用域进行预绑定。transclude链接函数是实际被执行用来客隆元素和操作DOM的函数
在控制器内部操作DOM是和Angular风格相悖的做饭,但通过链接函数就可以实现这个需求。仅在compile参数中使用transcludeFn是推荐的做法
此处,关于这个部分就不详细介绍了。
[5] controllerAs(字符串或函数)
controllerAs参数用来设置控制器的别名,可以在视图中引用控制器,无需注入$scope
。
如下例:
<div ng-controller='MainController as main'> <span>{{main.name}}</span> </div>
angular.module('myApp',[])
.controller('MainController',function() {
this.name='Amy';
});
这个参数可以在路由和指令中创建匿名控制器。可以将动态的对象创建成为控制器,并且这个对象是隔离的,易于测试的。如下:
<div my-directive></div>
angular.module('myApp',[])
.directive("myDirective",function() {
return {
restrict:"A",template:'<h4>{{myController.msg}}</h4>',controllerAs: 'myController',controller: function(){
this.msg='Hello World'
}
}
});
[5] require(字符串或数组)
require的作用是为了让父子指令或者兄弟指令的controller之间搭建一个桥梁。也就是说父指令里的controller里面的数据能分享给子指令的controller。
其中子指令的link第四个参数的值是父指令的controller对象的作用域上下文require有两个修饰符号:?
和^
。
- ? : 如果require没有找到相应的指令避免报错,还能确保程序的正常执行
- ^ : 表示往父级查找
(4) AngularJS生命周期
这部分书上有比较详细的说明,在此,仅介绍两个比较重要的部分compile和link。
compile可以安全的修改DOM,link则不能。换句话说,compile在修改了DOM后进行编译,link修改了DOM后不再自动编译。
[1] compile(对象或函数)
通常情况下,如果设置了compile函数,说明希望在指令和实时数据被放到DOM之前进行DOM操作,在这个函数中进行诸如添加和删除节点等DOM操作是安全的。
angular.module('myApp',function() {
return {
restrict: 'A',compile: function(tElem,tAttrs,transcludeFn){
}
}
});
[2] link
用link函数创建可以操作DOM的指令。
如果指令中有require选项,函数签名中会有第四个参数,代表控制器或者所以来的指令的控制器。
angular.module('myApp',require: 'SomeController',link: function(scope,element,attrs,SomeController){
}
}
});
参数: - scope: 指令用来在其内部注册监听器的作用域 - iElement: 代表实例元素,指使用此指令的元素。 - iAttrs: 代表实例属性,会以JavaScript对象的形式进行传递。 - controller: 指向require选项定义的控制器。如果没有设置require选项,这个参数值为undefined