媒介
近来进修了下angularjs指令的相干学问,也参考了前人的一些文章,在此总结下。
欢迎批评指出毛病的处所。
Angularjs指令定义的API
AngularJs的指令定义大抵以下
angular.module(“app”,[]).directive(“directiveName”,function(){
return{
//经由历程设置项来定义
};
})
个中return返回的对象包括许多参数,下面逐一说明
你晓得用AngularJs怎样定义指令吗?0
1.restrict
(字符串)可选参数,指明指令在DOM内里以什么情势被声明;
取值有:E(元素),A(属性),C(类),M(解释),个中默许值为A;
E(元素):<directiveName></directiveName>
A(属性):<div directiveName=’expression’></div>
C(类): <div class=’directiveName’></div>
M(解释):<–directive:directiveName expression–>
你晓得用AngularJs怎样定义指令吗?1
比方restrict:‘EA’ 则示意指令在DOM内里可用元素情势和属性情势被声明;
平常来讲,当你竖立一个有自身模板的组件的时刻,须要运用元素名,假如仅仅是为为已有元素增加功用的话,就运用属性名
注重:假如想支撑IE8,则最好运用属性和类情势来定义。 别的Angular从1.3.x最先, 已摒弃支撑IE8了.
2.priority
(数字),可选参数,指明指令的优先级,若在单个DOM上有多个指令,则优先级高的先实行;
设置指令的优先级算是不常常使用的
比较特别的的例子是,angularjs内置指令的ng-repeat的优先级为1000,ng-init的优先级为450;
3.terminal
(布尔型),可选参数,能够被设置为true或false,若设置为true,则优先级低于此指令的其他指令则无效,不会被挪用(优先级雷同的照样会实行)
4.template(字符串或许函数)可选参数,能够是:
(1)一段HTML文本
angular.module(“app”,[]).directive(“hello”,function(){
return{
restrict:'EA',
template:"<div><h3>hello world</h3></div>"
};
})
HTML代码为:<hello></hello>
效果衬着后的HTML为:<hello>
<div><h3>hello world</h3></div>
</hello>
(2)一个函数,可接受两个参数tElement和tAttrs
个中tElement是指运用此指令的元素,而tAttrs则实例的属性,它是一个由元素上一切的属性构成的鸠合(对象)形如:
{
title:‘aaaa’,
name:’leifeng’
}
下面让我们看看template是一个函数时刻的状况
angular.module(“app”,[]).directive(“directitle”,function(){
return{
restrict:'EAC',
template: function(tElement,tAttrs){
var _html = '';
_html += '<div>'+tAttrs.title+'</div>';
return _html;
}
};
})
HTML代码:<directitle title=’biaoti’></directitle>
衬着以后的HTML:<div>biaoti</div>
因为一段HTML文本,浏览跟保护起来都是很贫苦的,所用通常会运用templateUrl这个。
5.templateUrl(字符串或许函数),可选参数,能够是
(1)一个代表HTML文件途径的字符串
(2)一个函数,可接受两个参数tElement和tAttrs(大抵同上)
注重:在当地开辟时刻,须要运转一个效劳器,不然运用templateUrl会报错 Cross Origin Request Script(CORS)毛病
因为加载html模板是经由历程异步加载的,若加载大批的模板会拖慢网站的速率,这里有个技能,就是先缓存模板
你能够再你的index页面加载好的,将以下代码作为你页面的一部份包括在内里。
<script type=’text/ng-template’ id=’woshimuban.html’>
<div>我是模板内容</div>
</script>
这里的id属性就是被设置在templateUrl上用的。
另一种要领缓存是:
angular.module(“template.html”, []).run([“$templateCache”, function($templateCache) {
$templateCache.put(“template.html”,
"<div>wo shi mu ban</div>");
}]);
6.replace
(布尔值),默许值为false,设置为true时刻,我们再来看看下面的例子(对照下在template时刻举的例子)
angular.module(“app”,[]).directive(“hello”,function(){
return{
restrict:'EA',
replace:true,
template:"<div><h3>hello world</h3></div>"
};
})
HTML代码为:
<hello></hello>
衬着以后的代码:<div><h3>hello world</h3></div>
对照下没有开启replace时刻的衬着出来的HTML。发明<hello></hello>不见了。
别的当模板为纯文本(即template:”wo shi wen ben”)的时刻,衬着以后的html代码默许的为文本用span包括。
7.scope
可选参数,(布尔值或许对象)默许值为false,能够取值:
(1)默许值false。
示意继续父作用域;
(2)true
示意继续父作用域,并竖立自身的作用域(子作用域);
(3){}
示意竖立一个全新的断绝作用域;
7.1起首我们先来了解下scope的继续机制。我们用ng-controller这个指令举例,
我们都晓得ng-controller(内置指令)能够从父作用域中继续而且竖立一个新的子作用域。以下:
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-init=”aaa=’父亲'”>
parentNode:{{aaa}}
<div ng-controller="myController">
chrildNode: {{aaa}}
</div>
</div>
<script>
angular.module('myApp', [])
.controller('myController',function($scope){
$scope.aaa = '儿子'
})
</script>
</body>
</html>
这时候页面显现是
parentNode:父亲
chrildNode: 儿子
若去掉
$scope.aaa = ‘儿子’
则显现
parentNode:父亲
chrildNode: 父亲
注重:
1)若一个元素上有多个指令,运用了断绝作用域,则只需个中一个能够见效;
2)只需指令模板中的根元素才取得一个新的作用域,这时候刻,scope就被设置为true了;
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-init=”aaa=’父亲'”>
parentNode:{{aaa}}
<div class='one' ng-controller="myController">
chrildNode: {{aaa}}
<div class='two' ng-controller='myController2'>
{{aaa}}
</div>
</div>
</div>
<script>
angular.module('myApp', [])
.controller('myController',function($scope){
$scope.aaa = '儿子';
})
.controller('myController2',function($scope){
$scope.aaa = '孙女';
})
</script>
</body>
</html>
页面显现为:
parentNode:父亲
chrildNode: cunjieliu
孙女
上面中class为one谁人div取得了指令ng-controller=’myController‘所竖立的新的作用域;
而class为two谁人div取得了指令ng-controller=’myController2‘所竖立的新的作用域;
这就是“只需指令模板中的根元素才取得一个新的作用域”;
接下来我们经由历程一个简朴清楚明了的例子来说明scope取值差异的差异
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-controller=’MainController’>
父亲: {{name}}
<input ng-model="name" />
<div my-directive></div>
</div>
<script>
angular.module('myApp', [])
.controller('MainController', function ($scope) {
$scope.name = 'leifeng';
})
.directive('myDirective', function () {
return {
restrict: 'EA',
scope:false,//转变此处的取值,看看有什么差异
template: '<div>儿子:{{ name }}<input ng-model="name"/></div>'
};
});
</script>
</body>
</html>
顺次设置scope的值false,true,{},效果发明(人人别偷懒,着手尝尝哈)
当为false时刻,儿子继续父亲的值,转变父亲的值,儿子的值也随之变化,反之亦云云。(继续不断绝)
当为true时刻,儿子继续父亲的值,转变父亲的值,儿子的值随之变化,然则转变儿子的值,父亲的值稳定。(继续断绝)
当为{}时刻,没有继续父亲的值,所以儿子的值为空,转变任何一方的值均不能影响另一方的值。(不继续断绝)
tip:当你想要竖立一个可重用的组件时断绝作用域是一个很好的挑选,经由历程断绝作用域我们确保指令是‘自力’的,并能够轻松地插进去到任何HTML app中,而且这类做法防备了父作用域被污染;
7.2断绝作用域能够经由历程绑定战略来访问父作用域的属性。
下面看一个例子
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-controller=’MainController’>
<input type="text" ng-model="color" placeholder="Enter a color"/>
<hello-world></hello-world>
</div>
<script>
var app = angular.module('myApp',[]);
app.controller('MainController',function(){});
app.directive('helloWorld',function(){
return {
scope: false,
restrict: 'AE',
replace: true,
template: '<p style="background-color:{{color}}">Hello World</p>'
}
});
</script>
</body>
</html>
运转代码,并在input中输入色彩值,效果为
你晓得用AngularJs怎样定义指令吗?2
然则,但我们将scope设置为{}时刻,再次运转上面的代码能够发明页面并不能胜利完全显现!
缘由在于,这里我们将scope设置为{},产生了断绝作用域。
所以在template模板中{{color}}变成了依靠于自身的作用域,而不是依靠于父作用域。
因而我们须要一些要领来让断绝作用域能读取父作用域的属性,就是绑定战略。
下面我们就来探究设置这类绑定的几种要领
要领一:运用@(@attr)来举行单向文本(字符串)绑定
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-controller=’MainController’>
<input type="text" ng-model="color" placeholder="Enter a color"/>
<hello-world color-attr='{{color}}'></hello-world> //注重这里设置了color-attr属性,绑定了{{color}}
</div>
<script>
var app = angular.module('myApp',[]);
app.controller('MainController',function(){});
app.directive('helloWorld',function(){
return {
scope: {color:'@colorAttr'}, //指清楚明了断绝作用域中的属性color应当绑定到属性colorAttr
restrict: 'AE',
replace: true,
template: '<p style="background-color:{{color}}">Hello World</p>'
}
});
</script>
</body>
</html>
这类要领只能单向,经由历程在运转的指令的谁人html标签上设置color-attr属性,而且采纳{{}}绑定某个模子值。
注重,你也能够再这里直接绑定字符串的色彩值,如:color-attr=“red”;
然后你能够看到表达式{{color}}被赋值给了color-attr。
当表达式的值发生变化时,属性color-attr也会发生变化,所以也转变了断绝作用域中的属性color。
tips:假如绑定的断绝作用域属性名与元素的属性名雷同,则能够采用缺省写法。
html:
<hello-world color=”{{color}}”/>
js定义指令的片断:
app.directive(‘helloWorld’,function(){
return {
scope: {
color: '@'
},
...
//设置的余下部份
}
});
要领二:运用=(=attr)举行双向绑定
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-controller=’MainController’>
<input type="text" ng-model="color" placeholder="Enter a color"/>
{{color}}
<hello-world color='color'></hello-world> //注重这里的写法
</div>
<script>
var app = angular.module('myApp',[]);
app.controller('MainController',function(){});
app.directive('helloWorld',function(){
return {
scope:{color:'='},
restrict: 'AE',
replace: true,
template: '<div style="background-color:{{color}}">Hello World<div><input type="text" ng-model="color"></div></div>'
}
});
</script>
</body>
</html>
此处也相似上面采纳了缺省的写法。
这里须要注重的是,我们要直接在指令运转的谁人元素上设置属性时刻,是直接将 现实的作用域模子 赋值给该属性(这里就是color)
如许一个双向绑定被竖立了,转变任何一个input都邑转变另一个值。
你晓得用AngularJs怎样定义指令吗?3
要领三:运用&来挪用父作用域中的函数
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-controller=’MainController’>
<input type="text" ng-model="name" placeholder="Enter a color"/>
{{name}}
<hello-world saysomething999="say();" name="liucunjie"></hello-world> //注重这里
</div>
<script>
var app = angular.module('myApp',[]);
app.controller('MainController',function($scope){
$scope.say = function(){
alert('hello');
}
$scope.name = 'leifeng';
});
app.directive('helloWorld',function(){
return {
scope:{
saysomething:'&saysomething999',
name:'@'
},
restrict: 'AE',
replace: true,
template: '<button type="button" ng-bind="name" ng-init="saysomething();"></button>'
}
});
</script>
</body>
</html>
运转以后,弹出alert框。
8.transclude
(布尔值或许字符‘element’),默许值为false;
这个设置选项能够让我们提取包括在指令谁人元素内里的内容,再将它安排在指令模板的特定位置。
当你开启transclude后,你就能够运用ng-transclude来指清楚明了应当在什么处所安排transcluded内容
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<div ng-controller=’MainController’>
<div class='a'>
<p>china</p>
<hello-world>
{{name}}
</hello-world>
</div>
</div>
<script>
var app = angular.module('myApp',[]);
app.controller('MainController',function($scope){
$scope.name = 'leifeng';
});
app.directive('helloWorld',function(){
return {
scope:{},
restrict: 'AE',
transclude: true,
template: '<div class="b"><div ng-transclude>你看不见我</div></div>'
}
});
</script>
</body>
</html>
运转上面的代码,输出
china
leifeng
别的当开启transclude,会竖立一个新的transclude空间,而且继续了父作用域(纵然Scope设置为断绝作用域),
上面代码中的{{name}}是依靠于父作用域的,依然能被衬着出来,就申清楚明了这点。
我们再看看天生的html为下图所示,能够发明文本“你看不见我”消逝了,这是因为被transclude内容替代掉了。
这里的transclude内容就是{{name}}
你晓得用AngularJs怎样定义指令吗?4
接下来再来看看transclude的另一个取值transclude:“element”
那transclude:“element”与transclude:true有什么区分呢?
区分在于嵌入的内容,以上面的例子来讲,
当transclude:true时刻,嵌入的内容为{{name}},
而当transclude:“element”时刻,嵌入的内容为
<hello-world>
{{name}}
</hello-world>
没错,此时嵌入的内容为全部元素。
将上面代码transclude:true换成transclude:true后,再运转,你会发明效果并非和你想的一样
再次检察天生的html代码
你晓得用AngularJs怎样定义指令吗?5
你会发明指令绑定的元素被转换为了一个HTML解释
关于这方面的疑问能够检察 transclude: ‘element’ is useless without replace:true 猎取更多
解决方案是加上replace: true,就平常了
这时候再检察HTML代码
你晓得用AngularJs怎样定义指令吗?6
注重:在一个指令的模板template上只能说明一个ng-transclude。
OK,那末如今题目来了,假如我们想把嵌入部份屡次放入我们的模板中要怎样办?
则能够运用$transclude(背面再controller选项中会讲)
或许能够运用compile函数,内里有个transcludeFn参数(背面会讲)
或许运用link链接函数。。。
9.controller
能够是一个字符串或许函数。
如果为字符串,则将字符串当作是掌握器的名字,来查找注册在运用中的掌握器的组织函数
angular.module(‘myApp’, [])
.directive(‘myDirective’, function() {
restrict: ‘A’, // 一直须要
controller: ‘SomeController’
})
// 运用中其他的处所,能够是同一个文件或被index.html包括的另一个文件
angular.module(‘myApp’)
.controller(‘SomeController’, function($scope, $element, $attrs, $transclude) {
// 掌握器逻辑放在这里
});
也能够直接在指令内部的定义为匿名函数,一样我们能够再这里注入任何效劳($log,$timeout等等)
angular.module(‘myApp’,[])
.directive(‘myDirective’, function() {
restrict: ‘A’,
controller:
function($scope, $element, $attrs, $transclude) {
// 掌握器逻辑放在这里
}
});
别的另有一些特别的效劳(参数)能够注入
(1)$scope,与指令元素相干联的作用域
(2)$element,当前指令对应的 元素
(3)$attrs,由当前元素的属性构成的对象
(4)$transclude,嵌入链接函数,现实被实行用来克隆元素和操纵DOM的函数
注重: 除非是用来定义一些可复用的行动,平常不引荐在这运用。
指令的掌握器和link函数(背面会讲)能够举行交换。区分在于,掌握器主如果用来供应可在指令间复用的行动但link链接函数只能在当前内部指令中定义行动,且没法再指令间复用。
html代码: <my-site site=”” target=”_blank”>http://www.cnblogs.com/cunjie…雷锋叔叔的博客</my-site>
js代码:
<script>
angular.module('myApp',[]).directive('mySite', function () {
return {
restrict: 'EA',
transclude: true, //注重此处必需设置为true
controller:
function ($scope, $element,$attrs,$transclude,$log) { //在这里你能够注入你想注入的效劳
$transclude(function (clone) {
var a = angular.element('<a>');
a.attr('href', $attrs.site);
a.text(clone.text());
$element.append(a);
});
$log.info("hello everyone");
}
};
});
</script>
运转上面的代码就是
你晓得用AngularJs怎样定义指令吗?7
而且在掌握台下输出hello everyone
让我们看看$transclude();在这里,它能够吸收两个参数,第一个是$scope,作用域,第二个是带有参数clone的回调函数。
而这个clone现实上就是嵌入的内容(经由jquery包装),能够在它上做许多DOM操纵。
它另有最简朴的用法就是
<script>
angular.module('myApp',[]).directive('mySite', function () {
return {
restrict: 'EA',
transclude: true,
controller:
function ($scope, $element,$attrs,$transclude,$log) {
var a = $transclude(); //$transclude()就是嵌入的内容
$element.append(a);
}
};
});
</script>
注重:运用$transclude会天生一个新的作用域。
默许状况下,假如我们简朴有用$transclude(),那末默许的其作用域就是$transclude天生的作用域
然则假如我们有用$transclude($scope,function(clone){}),那末作用域就是directive的作用域了
那末题目又来了。假如我们想有用父作用域呢
能够运用$scope.$parent
<div ng-controller=’parentctrl’>
<div ng-controller='sonctrl'>
<my-site site="http://www.cnblogs.com/cunjieliu"><div>雷锋叔叔的博客</div></my-site>
</div>
</div>
<script>
var app = angular.module('myApp',[]);
app.controller('sonctrl',function($scope){
$scope.title = 'hello son';
});
app.controller('parentctrl',function($scope){
$scope.title = 'hello parent';
});
app.directive('mySite', function () {
return {
restrict: 'EA',
transclude: true,
controller:
function ($scope, $element,$attrs,$transclude,$log) {
var a = $transclude();
$element.append(a);
$log.info($scope.title);
$log.info($scope.$parent.title);
}
};
});
</script>
同理想要一个新的作用域也能够运用$scope.$parent.new();
10.controllerAs
这个选项的作用是能够设置你的掌握器的别号
平常之前我们经常常使用如许体式格局来写代码:
angular.module(“app”,[])
.controller(“demoController”,[“$scope”,function($scope){
$scope.title = "angualr";
}])
<div ng-app=”app” ng-controller=”demoController”>
{{title}}
</div>
厥后angularjs1.2给我们带来新语法糖,所以我们能够如许写
angular.module(“app”,[])
.controller(“demoController”,[function(){
this.title = "angualr";
}])
<div ng-app=”app” ng-controller=”demoController as demo”>
{{demo.title}}
</div>
一样的我们也能够再指令内里也如许写
<script>
angular.module('myApp',[]).directive('mySite', function () {
return {
restrict: 'EA',
transclude: true,
controller:'someController',
controllerAs:'mainController'
//..其他设置
};
});
</script>
11.require(字符串或许数组)
字符串代表另一个指令的名字,它将会作为link函数的第四个参数
详细用法我们能够举个例子说明
假定如今我们要编写两个指令,两个指令中的link链接函数中(link函数背面会讲)存在有许多重合的要领,
这时候刻我们就能够将这些反复的要领写在第三个指令的controller中(上面也讲到controller经常常使用来供应指令间的复用行动)
然后在这两个指令中,require这个具有controller字段的的指令(第三个指令),
末了经由历程link链接函数的第四个参数就能够援用这些重合的要领了。
<!doctype html>
<html ng-app=”myApp”>
<head>
<script src=”” target=”_blank”>http://cdn.staticfile.org/ang…
</head>
<body>
<outer-directive>
<inner-directive></inner-directive>
<inner-directive2></inner-directive2>
</outer-directive>
<script>
var app = angular.module('myApp', []);
app.directive('outerDirective', function() {
return {
scope: {},
restrict: 'AE',
controller: function($scope) {
this.say = function(someDirective) {
console.log('Got:' + someDirective.message);
};
}
};
});
app.directive('innerDirective', function() {
return {
scope: {},
restrict: 'AE',
require: '^outerDirective',
link: function(scope, elem, attrs, controllerInstance) {
scope.message = "Hi,leifeng";
controllerInstance.say(scope);
}
};
});
app.directive('innerDirective2', function() {
return {
scope: {},
restrict: 'AE',
require: '^outerDirective',
link: function(scope, elem, attrs, controllerInstance) {
scope.message = "Hi,shushu";
controllerInstance.say(scope);
}
};
});
</script>
</body>
</html>
上面例子中的指令innerDirective和指令innerDirective2复用了定义在指令outerDirective的controller中的要领
也进一步申清楚明了,指令中的controller是用来让差异指令间通信用的。
别的我们能够在require的参数值加上下面的某个前缀,这会转变查找掌握器的行动:
(1)没有前缀,指令会在自身供应的掌握器中举行查找,假如找不到任何掌握器,则会抛出一个error
(2)?假如在当前的指令没有找到所需的掌握器,则会将null传给link衔接函数的第四个参数
(3)^假如在当前的指令没有找到所需的掌握器,则会查找父元素的掌握器
(4)?^组合
12.Anguar的指令编译历程
起首加载angularjs库,查找到ng-app指令,从而找到运用的边境,
依据ng-app规定的作用域来挪用$compile效劳举行编译,
angularjs会遍历全部HTML文档,并依据js中指令的定义来处置惩罚在页面上声明的各个指令
根据指令的优先级(priority)分列,依据指令中的设置参数(template,place,transclude等)转换DOM
然后就最先按递次实行各指令的compile函数(假如指令上有定义compile函数)对模板自身举行转换
注重:此处的compile函数是我们指令中设置的,跟上面说的$compile效劳不一样。
每一个compile函数实行完后都邑返回一个link函数,一切的link函数会合成一个大的link函数
然后这个大的link函数就会被实行,主要做数据绑定,经由历程在DOM上注册监听器来动态修正scope中的数据,
或许是运用$watchs监听 scope中的变量来修正DOM,从而竖立双向绑定等等。
若我们的指令中没有设置compile函数,那我们设置的link函数就会运转,
她做的事变大抵跟上面complie返回以后一切的link函数合成的的大的link函数差不多。
所以:在指令中compile与link选项是互斥的,假如同时设置了这两个选项,
那末就会把compile所返回的函数当作是链接函数,而link选项自身就会被疏忽掉
13.compile编译函数和link链接函数
13.1compile编译函数选项
compile选项能够返回一个对象或许函数
在这里我们能够在指令和及时数据被放到DOM中之前举行DOM操纵,
比方我们能够在这里举行增加或许删除节点的DOM的操纵。
所以编译函数是担任对模板的DOM举行转换,而且仅仅只会运转一次。
//compile函数的语法
compile:function compile(tElement,tAttrs,transclude){
return{
pre:function preLink(scope,iElement,iAttrs,controller){},
post:function postLink(scope,iElement,iAttrs,controller){}
}
}
关于我们编写的大部份的指令来讲,并不须要对模板举行转换,所以大部份状况只需编写link函数就能够了。
tips:preLink函数会在编译阶段以后,指令链接到子元素之前实行
相似的,postLink会在指令链接到子元素以后实行
这意味着,为了不损坏绑定历程,假如你须要修正DOM构造,你应当在postLink函数中来做这件事。
13.2link链接函数选项
链接函数担任将作用域和DOM举行链接。
//link链接函数
link:function postLink(scope,iElement,iAttrs){}
若指令中定义有require选项,则link函数会有第四个参数,代表掌握器或许所依靠的指令的掌握器(上面require选项例子已有例子)