原地址:http://blog.csdn.net/evankaka/article/details/51233555
此文接 跟我学AngularJs:Directive指令用法解读(上)
8.transclude
如果不想让指令内部的内容被模板替换,可以设置这个值为true。一般情况下需要和ngTransclude指令一起使用。 比如:template:"
",这时,指令内部的内容会嵌入到ng-transclude这个div中。也就是变成了
。默认值为false;这个配置选项可以让我们提取包含在指令那个元素里面的内容,再将它放置在指令模板的特定位置。当你开启transclude后,你就可以使用ng-transclude来指明了应该在什么地方放置transcluded内容
- >
- <html lang="zh" ng-app="myApp">
- <head>
- <meta charset="UTF-8">
- <title>AngularJS入门学习title>
- <script type="text/javascript" src="./1.5.3/angular.min.js">script>
- head>
- <div sidebox title="Links">
- <ul>
- <li>First linkli>
- <li>Second linkli>
- ul>
- div>
- body>
- <script type="text/javascript">
- var app = angular.module('myApp', []);
- app.directive('sidebox', function() {
- return {
- restrict: 'EA',
- scope: {
- title: '@'
- },
- transclude: true,
- template: '<div class="sidebox">\
- <div class="content">\
- <h2 class="header">{{ title }}h2>\
- <span class="content" ng-transclude>\
- span>\
- div>\
- div>'
- };
- });
- script>
- html>
结果:
当 transclude: false,时
如果指令使用了transclude参数,那么在控制器无法正常监听数据模型的变化了。建议在链接函数里使用$watch服务。
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 lang="zh" ng-app="myApp">
- <head>
- <meta charset="UTF-8">
- <title>AngularJS入门学习title>
- <script type="text/javascript" src="./1.5.3/angular.min.js">script>
- head>
- <hello mycolor ="red">我是林炳文~~~hello>
- body>
- <script type="text/javascript">
- var app = angular.module('myApp', []);
- app.directive('hello', function() {
- return {
- restrict: 'EA',
- transclude: true, //注意此处必须设置为true
- controller:
- function ($scope, $element,$attrs,$transclude,$log) { //在这里你可以注入你想注入的服务
- $transclude(function (clone) {
- var a = angular.element('<p>');
- a.css('color', $attrs.mycolor);
- a.text(clone.text());
- $element.append(a);
- });
- $log.info("hello everyone");
- }
- };
- });
- script>
- html>
输出结果:
并且在控制台下输出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
同理想要一个新的作用域也可以使用$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链接函数的第四个参数就可以引用这些重合的方法了。
- >
- <html ng-app="myApp">
- <head>
- <script src="http://cdn.staticfile.org/angular.js/1.2.10/angular.min.js">script>
- 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 function
function compile(tElement, tAttrs, transclude) { ... }
编译函数是用来处理需要修改模板DOM的情况的。因为大部分指令都不需要修改模板,所以这个函数也不常用。需要用到的例子有ngTrepeat,这个是需要修改模板的,还有ngView这个是需要异步载入内容的。编译函数接受以下参数。
tElement - template element - 指令所在的元素。对这个元素及其子元素进行变形之类的操作是安全的。
tAttrs - template attributes - 这个元素上所有指令声明的属性,这些属性都是在编译函数里共享的。
transclude - 一个嵌入的链接函数function(scope, cloneLinkingFn)。
注意:在编译函数里面不要进行任何DOM变形之外的操作。 更重要的,DOM监听事件的注册应该在链接函数中做,而不是编译函数中。
编译函数可以返回一个对象或者函数。
返回函数 - 等效于在编译函数不存在时,使用配置对象的link属性注册的链接函数。
返回对象 - 返回一个通过pre或post属性注册了函数的对象。参考下面pre-linking和post-liking函数的解释。
14、链接函数 Linking function
function link(scope, iElement, iAttrs, controller) { ... }
链接函数负责注册DOM事件和更新DOM。它是在模板被克隆之后执行的,它也是大部分指令逻辑代码编写的地方。
scope - 指令需要监听的作用域。
iElement - instance element - 指令所在的元素。只有在postLink函数中对元素的子元素进行操作才是安全的,因为那时它们才已经全部链接好。
iAttrs - instance attributes - 实例属性,一个标准化的、所有声明在当前元素上的属性列表,这些属性在所有链接函数间是共享的。
controller - 控制器实例,也就是当前指令通过require请求的指令direct2内部的controller。比如:direct2指令中的controller:function(){this.addStrength = function(){}},那么,在当前指令的link函数中,你就可以通过controller.addStrength进行调用了。
Pre-linking function 在子元素被链接前执行。不能用来进行DOM的变形,以防链接函数找不到正确的元素来链接。
Post-linking function 所有元素都被链接后执行。
说明:
compile选项本身并不会被频繁使用,但是link函数则会被经常使用。本质上,当我们设置了link选项,实际上是创建了一个postLink() 链接函数,以便compile() 函数可以定义链接函数。通常情况下,如果设置了compile函数,说明我们希望在指令和实时数据被放到DOM中之前进行DOM操作,在这个函数中进行诸如添加和删除节点等DOM操作是安全的。compile和link选项是互斥的。如果同时设置了这两个选项,那么会把compile所返回的函数当作链接函数,而link选项本身则会被忽略。译函数负责对模板DOM进行转换。链接函数负责将作用域和DOM进行链接。 在作用域同DOM链接之前可以手动操作DOM。在实践中,编写自定义指令时这种操作是非常罕见的,但有几个内置指令提供了这样的功能。 链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义时,编译函数会重载链接函数。如果我们的指令很简单,并且不需要额外的设置,可以从工厂函数(回调函数)返回一个函数来代替对象。如果这样做了,这个函数就是链接函数。