例子创建了一个指令,当AngularJS 找到一个 <userinfo> 元素的时候就会激活它。AngularJS 加载指向 /myapp/html-templates/userinfo-template.html 的模板并解析它,它就像从一开始就被嵌在上一级 HTML 文件中一样。
从指令中隔离 $scope
在上面的例子中,把 userinfo 指令硬绑定到了 $scope ,因为 HTML 模板是直接引用 textToInsert 属性的。直接引用 $scope 让指令在同一个 controller 中的时候,非常难复用,因为 $scope在同一个 controller 中的值都是一样的。比如说,你在页面的 HTML 中这样写的时候:
<!-- lang: js --> <userinfo></userinfo> <userinfo></userinfo>
这两个 <userinfo> 元素会被同样的 HTML 模板取代,然后绑定到同样的 $scope 变量上。结果就是两个 <userinfo> 元素将会被一模一样的 HTML 代码给替换了。
为了把两个 <userinfo> 元素绑定到 $scope 中的不同的值,你需要给 HTML 模板一个 isolate scope。
所谓 isolate scope 是绑定在指令上的独立的 scope 对象。下面是定义的例子:
<!-- lang: js --> myapp.directive('userinfo', function() { var directive = {}; directive.restrict = 'E'; directive.template = "User : {{user.firstName}} {{user.lastName}}"; directive.scope = { user : "=user" } return directive; })
请看 HTMl 模板中的两个内插指令 {{user.firstName}} 和 {{user.lastName}}。注意 user. 部分。以及directive.scope 属性。 directive.scope 是个带 user 属性的 Javascript 对象。于是directive.scope 就成为了 isolate scope 对象,现在 HTML 模板被绑到了 directive.scope.user 上(通过 {{user.firstName}} 和 {{user.lastName}} 内插指令)。
directive.scope.user 被设置为 “=user” 。意思是说 directive.scope.user 和 scope 中的属性绑在一起的(不是 isolate scope),scope 中的属性通过 user 属性传入 <userinfo> 元素。听起来挺费劲的,直接看例子:
<!-- lang: js --> <userinfo user="jakob"></userinfo> <userinfo user="john"></userinfo>
这两个 <userinfo> 元素都有 user 属性。user 的值指向了 $scope 中同名属性,被指定的 $scope中的属性将在 userinfo 的 isolate scope object 中被使用。
下面是完整的例子:
<!-- lang: js --> <userinfo user="jakob"></userinfo> <userinfo user="john"></userinfo> <script> myapp.directive('userinfo', function() { var directive = {}; directive.restrict = 'E'; directive.template = "User : <b>{{user.firstName}}</b> <b>{{user.lastName}}</b>"; directive.scope = { user : "=user" } return directive; }); myapp.controller("MyController", function($scope, $http) { $scope.jakob = {}; $scope.jakob.firstName = "Jakob"; $scope.jakob.lastName = "Jenkov"; $scope.john = {}; $scope.john.firstName = "John"; $scope.john.lastName = "Doe"; }); </script>
compile() 和 link() 函数
如果你需要在你的指令中做更高级的操作,单纯使用 HTML 模板做不到的时候,你可以考虑使用compile() 和 link() 函数。
compile() 和 link() 函数定义了指令如何修改匹配到的 HTML。
当指令第一次被 AngularJS 编译的时候 (在 HTML 中第一次被发现),compile() 函数被调用。compile() 函数将为该元素做一次性配置。
然后 compile() 函数以返回 link() 作为终结。link() 函数将在每次元素被绑到 $scope 数据时,都被调用。
下面是例子:
<!-- lang: js --> <script> myapp = angular.module("myapp", []); myapp.directive('userinfo', function() { var directive = {}; directive.restrict = 'E'; /* restrict this directive to elements */ directive.compile = function(element, attributes) { // do one-time configuration of element. var linkFunction = function($scope, element, atttributes) { // bind element to data in $scope } return linkFunction; } return directive; }); </script>
compile() 函数带两个参数: element 和 attributes。
element 参数是 jqLite 包装过的 DOM 元素。AngularJS 有一个简化版 jQuery 可以用于操作 DOM,所以对 element 的 DOM 操作方式和你在 jQuery 中所知的一样。
attributes 参数是包含了 DOM 元素中的所有的属性集合的 Javascript 对象。因此,你要访问某个属性你可以这样写 attributes.type。
link() 函数带三个参数: $scope,element 和 attributes。element 和attributes 参数和传到 compile() 函数中的一样。$scope 参数是正常的 scope 对象,或者当你在指令定义对象中定义了 isolate scope 的时候,它就是 isolate scope。