Best Practice: 为了避免与某些未来的标准命名冲突,最好前缀化你自己的指令,比如你创建一个<carousel>指令,它可能会产生冲突,加入HTML7引入相同的元素。推荐使用两三个单词的前缀(比如btfCarousel),同样不能使用ng或者其他可能与angular未来版本起冲突的前缀。
以下的例子中,我们统一使用my前缀。
模板扩展的指令
当你有大量代表客户信息的模板。这个模板在你的代码中重复了很多次,当你改变一个地方的时候,你不得不在其他地方同时改动,这时候,你就要使用指令来简化你的模板。
我们来创建一个指令,简单的时候静态模板来替换它的内容。
<div ng-controller="Ctrl"> <div my-customer></div> </div>
JS
angular.module('docsSimpleDirective', []) .controller('Ctrl', function($scope) { $scope.customer = { name: 'Naomi', address: '1600 Amphitheatre' }; }) .directive('myCustomer', function() { return { template: 'Name: {{customer.name}} Address: {{customer.address}}' }; });
注意我们这里做了一些绑定,$compile编译链接<div my-customer> </div>之后,它将会匹配子元素的指令。这意味着你可以组合一些指令。以下例子中你会看到如何做到这一点。
这个例子中,我们直接在template配置项里写上模板,但是随着模板大小的增加,这样非常不优雅。
Best Practice: 除非你的模板非常小,否则更好的是分割成单独的hmtl文件,然后使用templateUrl选项来加载。
假如你熟悉ngInclude,templateUrl跟它非常类似。现在我们使用templateUrl方式重写上面的例子:
<div ng-controller="Ctrl"> <div my-customer></div> </div>
JS:
angular.module('docsTemplateUrlDirective', []) .controller('Ctrl', function($scope) { $scope.customer = { name: 'Naomi', address: '1600 Amphitheatre' }; }) .directive('myCustomer', function() { return { templateUrl: 'my-customer.html' }; });
my-customer.html
Name: {{customer.name}} Address: {{customer.address}}
非常好,但是如果我们想让我们的指令匹配标签名<my-customer>? 如果我们只是简单的把<my-customer>元素放在hmtl上面,会发现没有效果。
Note: 创建指令的时候,默认仅使用属性的方式。为了创建一个能由元素名字触发的指令,你需要用到restrict配置。
restrict配置可以按如下方式设置:
-'A' 仅匹配属性名字
-'E' 仅匹配元素名字
-'AE' 可以匹配到属性名字或者元素名
所以,我们可以使用 restrict: 'E'配置我们指令。
<div ng-controller="Ctrl"> <div my-customer></div> </div>
JS
angular.module('docsTemplateUrlDirective', []) .controller('Ctrl', function($scope) { $scope.customer = { name: 'Naomi', address: '1600 Amphitheatre' }; }) .directive('myCustomer', function() { return { restrict: 'E', templateUrl: 'my-customer.html' }; });
my-customer.html
Name: {{customer.name}} Address: {{customer.address}}
Note: 什么时候使用属性名或元素名呢? 当创建一个含有自己模板的组件的时候,需要使用元素名,如果仅仅是为已有的元素添加功能的话,使用属性名。
使用元素名做为myCustomer指令是非常正确的决定,因为你不是用一些'customer'行为来点缀元素,而是定义一个具有自己行为的元素作为customer组件。
隔离指令的作用域
上面我们的myCustomer指令已经非常好了,但是它有个致命的缺陷,我们在给定的作用域内仅能使用一次。
它现在的实现是,我们每次重用该指令的时候都要为它新创一个控制器。
<div ng-controller="NaomiCtrl"> <my-customer></my-customer> </div> <hr> <div ng-controller="IgorCtrl"> <my-customer></my-customer> </div>
JS
angular.module('docsScopeProblemExample', []) .controller('NaomiCtrl', function($scope) { $scope.customer = { name: 'Naomi', address: '1600 Amphitheatre' }; }) .controller('IgorCtrl', function($scope) { $scope.customer = { name: 'Igor', address: '123 Somewhere' }; }) .directive('myCustomer', function() { return { restrict: 'E', templateUrl: 'my-customer.html' }; });
my-customer.html
Name: {{customer.name}} Address: {{customer.address}}
这很明显不是一个好的解决方案。
我们想要做的是能够把指令的作用域与外部的作用域隔离开来,然后映射外部的作用域到指令内部的作用域。可以通过创建isolate scope来完成这个目的。这样的话,我们使用指令的scope配置。
<div ng-controller="Ctrl"> <my-customer customer="naomi"></my-customer> <hr> <my-customer customer="igor"></my-customer> </div>
JS