指令(Directive)能够说是 AngularJS
的核心,而其开发也是比较困难的,本文主要介绍指令的一些参数和scope的绑定策略。html
从 AngularJS 的官方文档中看到指令的参数以下:ajax
{ priority: 0, template: '<div></div>', // or // function(tElement, tAttrs) { ... }, // or // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, transclude: false, restrict: 'A', scope: false, controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, controllerAs: 'stringAlias', require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } // or // return function postLink( ... ) { ... } }, // or // link: { // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, // post: function postLink(scope, iElement, iAttrs, controller) { ... } // } // or // link: function postLink( ... ) { ... } }
下面详细讲解每一个参数。缓存
priority(Number)
指令执行的优先级,用于多个指令同时做用于同一个元素时。例如:cookie
<select> <option ng-repeat="i in [1, 2]" ng-bind="i"></option> </select>
上面的例子中,ng-repeat
指令和 ng-bind
指令同时做用于 option
元素,因为 ng-repeat
的 priority 为1000,ng-bind
的 priority 为0,所以先执行 ng-repeat
,而后变量 i 的值才能用于 ng-bind 中。app
template(String or Function)
HTML模板内容,用于下列状况之一:函数
替换元素的内容(默认状况)。post
替换元素自己(若是 replace 选项为 true)。ui
将元素的内容包裹起来(若是 transclude 选项为 true,后面会细说)。url
值能够是:spa
一个 HTML 字符串。例如:<div>my name is {{name}}</div>
。
一个函数,接收两个参数 tElement(元素自己) 和 tAttrs(元素的属性集合),返回 HTML 字符串。
templateUrl(String or Function)
templateUrl 和 template 做用相同,但模板内容是从 $templateCache 服务或远程 url 加载。
值能够是:
一个字符串,AngularJS
会先从 $templateCache
中查找是否缓存了对应值,若是没有则尝试 ajax 加载。例如:在页面中有以下 script:
<script type="text/ng-template" id="Hello.html"> <p>Hello</p> </script>
AngularJS 会将 type="text/ng-template"
的 script
标签中的内容以 id 值为 key 缓存到 $templateCache 服务中,此时能够设置 templateUrl: 'Hello.html'
。
一个函数,接收两个参数 tElement(元素自己) 和 tAttrs(元素的属性集合),返回 url 地址。
transclude(Boolean)
官方文档的解释为:编译元素的内容,使其在指令内部可用。该选项通常和 ng-transclude
指令一块儿使用。
若是 transclude 设置为 true,则元素的内容会被放到模板中设置了 ng-transclude
指令的元素中。例如:
app.directive('testTransclude', [ function () { return { restrict: 'E', transclude: true, template: '<div>\ <p>指令内部段落</p>\ <div ng-transclude></div>\ </div>' }; } ]);
<test-transclude> <p>该段落会被放到指令内部</p> </test-transclude>
上面生成后的 DOM 结构为:
restrict(String)
指令的使用形式。
值能够为:
'E'
- 指令做为元素使用
'A'
- 指令做为属性使用
'C'
- 指令做为类名使用
'M'
- 指令做为注释使用(不经常使用)
能够是以上值的组合,如 restrict: 'EA'
表示指令既能够做为属性使用,也能够做为元素使用。
scope(Boolean or Object)
关于 scope 选项将会在后面的指令 scope 中细说。
controller(Function)
通常状况下不须要使用指令的 controller
,只要使用 link
就够了,后面会细说 link 函数。
用 controller
的场景是该指令(a)会被其余指令(b)require
的时候,在 b 的指令里能够传入 a 的这个 controller,目的是为了指令间的复用和交流。而 link
只能在指令内部中定义行为,没法作到这样。
controllerAs(String)
为控制器指定别名,这样能够在须要控制器的地方使用该名字进行注入。
require(String or Array)
表示指令依赖于一个或多个指令,并注入所依赖指令的控制器到 link
函数的第四个参数中。若是所依赖的指令不存在,或所依赖指令的控制器不存在则会报错。
依赖名称前缀能够为:
(没有前缀) - 在当前元素中查找依赖指令的控制器,若是不存在则报错。
?
- 在当前元素中查找依赖指令的控制器,若是不存在传 null
到 link
中。
^
- 在当前元素及父元素中查找依赖指令的控制器,若是不存在则报错。
?^
- 在当前元素及父元素中查找依赖指令的控制器,若是不存在传 null
到 link
中。
例子:
app.directive('validate', [ function () { return { restrict: 'A', require: 'ngModel', link: function (scope, ele, attrs, ngModelCtrl) { // 监听值变化 ngModelCtrl.$viewChangeListeners.push(function () { scope.validateResult = ngModelCtrl.$viewValue === 'Heron'; }); } }; } ]); app.controller('myCtrl', [ '$scope', '$cookieStore', function ($scope, $cookieStore) { $scope.name = 'Heron'; $scope.sayHi = function (name, age) { alert('Hello ' + name + ', your age is ' + age); } } ]);
<div ng-controller="myCtrl"> <input type="text" ng-model="name" validate> <p> validate 结果:{{validateResult}} </p> </div>
运行结果如图:
compile(Function)
和 link(Function)
建立的建立过程能够分为编译(compile)阶段和连接(link)阶段,所以二者放一块儿讲。
二者区别在于:
compile
函数的做用是对指令的模板进行转换。
link
函数的做用是在视图和模型之间创建关联,包括注册事件监听函数和更新 DOM
操做。
scope
在连接阶段才会被绑定到元素上,所以 compile
函数中没有入参 scope
。
对于同一个指令的多个示例,compile
函数只会执行一次,而 link
函数在每一个实例中都会执行。
若是自定义了 compile
函数,则自定义的 link
函数 无效,而是使用 compile
函数 返回的 link
函数。
scope 选项有三种值:
false
- 使用父 scope
。改变父 scope
会影响指令 scope
,反之亦然。
true
- 继承父 scope
,并建立本身的 scope
。改变父 scope
会影响指令 scope
,而改变指令 scope
不会影响父 scope
。
{}
- 不继承父 scope
,建立独立的 scope
。若是不使用双向绑定策略(后面会讲),改变父 scope
不会影响指令 scope
,反之亦然。
例子:
app.controller('myCtrl', [ '$scope', '$cookieStore', function ($scope, $cookieStore) { $scope.scopeFalse = 'Heron'; $scope.scopeTrue = 'Heron'; $scope.scopeObject = 'Heron'; } ]); app.directive('directiveFalse', [ function () { return { restrict: 'EA', scope: false, template: '<div>\ <p>\ <span>指令 scope: </span>\ <input type="text" ng-model="scopeFalse">\ </p>\ </div>' }; } ]); app.directive('directiveTrue', [ function () { return { restrict: 'EA', scope: true, template: '<div>\ <p>\ <span>指令 scope: </span>\ <input type="text" ng-model="scopeTrue">\ </p>\ </div>' }; } ]); app.directive('directiveObject', [ function () { return { restrict: 'EA', scope: {}, template: '<div>\ <p>\ <span>指令 scope: </span>\ <input type="text" ng-model="scopeObject">\ </p>\ </div>', link: function (scope) { // 因为使用独立scope,所以须要本身定义变量 scope.scopeObject = 'Heron'; } }; } ]);
<div ng-controller="myCtrl"> <h3>scope: false</h3> <p> <span>父 scope: </span> <input type="text" ng-model="scopeFalse"> </p> <directive-false></directive-false> <h3>scope: true</h3> <p> <span>父 scope: </span> <input type="text" ng-model="scopeTrue"> </p> <directive-true></directive-true> <h3>scope: {}</h3> <p> <span>父 scope: </span> <input type="text" ng-model="scopeObject"> </p> <directive-object></directive-object> </div>
运行结果如图:
针对独立 scope,能够经过在对象中声明如何从外部传入参数。有如下三种绑定策略:
@
- 使用 DOM 属性值单项绑定到指令 scope
中。此时绑定的值老是一个字符串,由于 DOM
的属性值是一个字符串。
<div my-directive age="26"></div> scope: { age: '@' }
=
- 在父 scope
和指令 scope
之间创建双向绑定。
<div my-directive age="age"></div> scope: { age: '=' }
&
- 使用父 scope
的上下文执行函数。通常用于绑定函数。
<div my-directive sayHi="sayHi()"></div> scope: { sayHi: '&' }
绑定函数时,有时须要向指令外部传递参数,以下:
app.controller('myCtrl', [ '$scope', '$cookieStore', function ($scope, $cookieStore) { $scope.name = 'Heron'; $scope.sayHi = function (name, age) { alert('Hello ' + name + ', your age is ' + age); }; } ]); app.directive('myDirective', [ function () { return { restrict: 'E', replace: true, scope: { clickMe: '&' }, template: '<div>\ <button class="btn btn-info" ng-click="clickMe({ age: age })">点我</button>\ </div>', link: function (scope) { scope.age = 26; } }; } ]);
<div ng-controller="myCtrl"> <my-directive click-me="sayHi(name, age)"></my-directive> </div>
运行结果如图:
说明一下:首先声明 clickMe: '&'
使用父 scope 的环境执行 clickMe 函数,而后在传递给指令时声明 click-me="sayHi(name, age)"
,表示父 scope 的 sayHi
方法须要两个参数,一个是 name,一个是 age,而后再指令中使用对象 {} 的方式向外传递参数,如 ng-click="clickMe({ age: age })"
,表示向指令外传递 age 参数,sayHi 方法从指令拿到 age 参数,再从本身的上下文中拿到 name 参数。
AngularJS 指令的开发和使用变幻无穷,也有许多坑,但愿你们留意,也但愿你们能在评论区多多交流心得。