一、指令基础
当浏览器加载一个包含AngularJS应用的HTML时,我们只需要用内置指令ng-app启动AngularJS应用,并标记出应用的根节点,这个指令需要以属性的形式来使用,因此可以将它写到任何位置,但是写到的开始标签上是最常规的做法:
任何在这个根元素内部的指令只要能够访问作用域,就可以访问$rootScope。
2.自定义指令
通过AngularJS模块API中的.directive()方法,我们可以通过传入一个字符串和一个函数来注册一个新指令。其中字符串是这个指令的名字,指令名应该是驼峰命名风格的,函数应该返回
一个对象。directive()方法返回的对象中包含了用来定义和配置指令所需的方法和属性。
angular.module('myApp',[]) .directive('myDirective', function() { return { restrict: 'E', template: ' Click me to go to Google' //为了尽快掌握简单的属性定义,我们只用了restrict和template两个设置项来定义指令 }; });
为了让AngularJS能够调用我们的指令,需要修改指令定义中的restrict设置。这个设置告、诉AngularJS在编译HTML时用哪种声明格式来匹配指令定义。我们可以指定一个或多个格式。可以以元素(E) 、属性(A) 、类(C)或注释(M)的格式来调用指令,建议用属性A(在已有的标签上添加功能)和元素(使用模板的时候)的方式来调用。
AngularJS在页面加载以及调用指令定义后生成的代码, AngularJS把生成后的代码提供给Chrome进行渲染。默认情况下, AngularJS将模板生成的HTML代码嵌套在自定义标签
向指令定义中添加一些新的设置:我们可以将自定义标签从生成的DOM中完全移除掉,
并只留下由模版生成的链接。将replace设置为true就可以实现这个效果:
angular.module('myApp', []) .directive('myDirective', function() { return { restrict: 'E', replace: true, template: 'Click me to go to Google' }; });
当AngularJS启动应用时,它会把第一个参数当作一个字符串,并以此字符串为名来注册第二个参数返回的对象。 AngularJS编译器会解析主HTML的DOM中的元素、属性、注释和CSS类名中使用了这个名字的地方,并在这些地方引用对应的指令。当它找到某个已知的指令时,就会在页面中插入指令所对应的DOM元素。
template参数是可选的,必须被设置为以下两种形式之一:
? 一段HTML文本;
? 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符串。
如果模板字符串中含有多个DOM元素,或者只由一个单独的文本节点构成,那它必须被包含在一个父元素内。换句话说,必须存在一个根DOM元素:
template: '\
另外,注意每一行末尾的反斜线,这样AngularJS才能正确解析多行字符串。
templateUrl是可选的参数,可以是以下类型:
? 一个代表外部HTML文件路径的字符串;
? 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件路径的字符串。
默认情况下,调用指令时会在后台通过Ajax来请求HTML模板文件。有两件事情需要知道。
? 在本地开发时,需要在后台运行一个本地服务器,用以从文件系统加载HTML模板,否则会导致Cross Origin Request Script(CORS)错误。
? 模板加载是异步的,意味着编译和链接要暂停,等待模板加载完成。
我们自定义指令是为了复用,肯定会用在不同的controller里面。为了在不同的控制器里面使用自定义指令,需要为指令增加配置项attr,指令怎么根据配置项调用不同控制器的方法?见下第5条:link
3.向指令中传递数据
注意,我们在模板中硬编码了URL和链接文本:
template:' Click me to go to Google'
我们的目标是关注指令的公共接口,就像其他任何编程语言一样。实际上,应该将上面的模板转换成可以接受两个变量的形式:一个变量是URL,另一个是链接文本:
template: '{{ myLinkText }}'
在主HTML文档中,可以给指令添加myUrl和myLinkText两个属性,这两个参数会成为指令内部作用域的属性:
有好几种途径可以设置指令内部作用域中属性的值。最简单的方法就是使用由所属控制器提供的已经存在的作用域。如果控制器被移除,或者在控制器的作用域中也定义了一个叫myUrl的属性,AngularJS 允许通过创建新的子作用域或者隔离作用域来解决这个常见问题。
angular.module('myApp', []) .directive('myDirective', function() { return { restrict: 'A', replace: true, scope: { myUrl: '@', //绑定策略 myLinkText: '@' //绑定策略 }, template: '' +'{{myLinkText}}' }; });
4.缓存
在模板第一次被引用时,它会被载入到模板缓存中以便快速的检索。angular直接通过 $templateCache 服务
5.link 方法:
回顾:
directive中的几个属性:
restrict
E: 表示该directive仅能以element方式使用,即:
A: 表示该directive仅能以attribute方式使用,即:
compile在编译前执行,负责把template(包括transclude所引用的)变成一个完整的DOM结构。 link在编译后执行, 负责根据controller和scope里的东东,给compile得到的DOM注册事件、关联数据,或者repeat之。
link里面有三个参数:
第一个参数scope基本上就是上面写的那个scope。
element简单说就是$(‘my-dialog’)
attrs是个map,内容是你这个directive上的所有属性,
require 之后,link就会多一个参数(第四个参数,scope,element,attrs,superCon)
当有两种加载方式时,可以给自定义指令增加属性:
指令内部怎么获取到哪种加载方式呢?attr!直接写属性小写名,不要加括号
那什么时候把逻辑写在controller里,什么时候写在link里呢?
如果想让方法暴露出结果,在外部被调用,则写在controller里
link是处理指令内部的事物的,比如给元素绑定事件、数据
6.指令间的交互
通过require以及link第四个参数superCon:
var myModule = angular.module("MyModule", []); myModule.directive("superman", function() { return { scope: {}, //创建独立作用域 restrict: 'AE', controller: function($scope) { $scope.abilities = []; this.addStrength = function() { $scope.abilities.push("strength"); }; this.addSpeed = function() { $scope.abilities.push("speed"); }; this.addLight = function() { $scope.abilities.push("light"); }; }, link: function(scope, element, attrs) { element.addClass('btn btn-primary'); element.bind("mouseenter", function() { console.log(scope.abilities); }); } } }); myModule.directive("strength", function() { return { require: '^superman',//把supermanCtrl自动注入到指令中,就可以调用superman控制器中的方法了 link: function(scope, element, attrs, supermanCtrl) { supermanCtrl.addStrength(); } } }); myModule.directive("speed", function() { return { require: '^superman', link: function(scope, element, attrs, supermanCtrl) { supermanCtrl.addSpeed(); } } }); myModule.directive("light", function() { return { require: '^superman', link: function(scope, element, attrs, supermanCtrl) { supermanCtrl.addLight(); } } });
页面代码:
7、创建独立scope
为了使指令相互独立使用,我们应该在return里面创建独立scope:
myModule.directive("superman", function() { return { scope: {}, //创建独立作用域 restrict: 'AE', controller: function($scope) { } } });