AngularJs中directive自定义指令angular.module("app",[]).directive("directiveName",function(){ return{ //通过设置项来定义 }; })[封装组件调用]

 

AngularJs的directive指令定义大致如下

angular.module("app",[]).directive("directiveName",function(){ 
 return{ 
 //通过设置项来定义 
 }; 
})

Directive可以放置于元素名、属性、class、注释中。下面是引用myDir这个directive的等价方式。(但很多directive都限制为“属性”的使用方式)

<span <span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span><span style="font-family: Arial, Helvetica, sans-serif;">="exp"></span>//属性</span> 
  
<span class="<span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span>: exp;"></span>//class 
  
<<span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span>></<span style="font-family: Arial, Helvetica, sans-serif;">directive-name</span>>//元素 
  
<!-- directive: <span style="font-family: Arial, Helvetica, sans-serif;">directive-name </span><span style="font-family: Arial, Helvetica, sans-serif;">exp -->//注释</span>

二、Directive指令内容解读

可 以看到它有8个内容

1.restrict
(字符串)可选参数,指明指令在DOM里面以什么形式被声明;取值有:E(元素),A(属性),C(类),M(注释),其中默认值为A;当然也可以两个一起用,比如EA.表示即可以是元素也可以是属性。
[html] view plain copy 在CODE上查看代码片派生到我的代码片
E(元素):<directiveName></directiveName>  
A(属性):<div directiveName='expression'></div>  
C(类): <div class='directiveName'></div>  
M(注释):<--directive:directiveName expression-->  
一般情况下E/A/C用得比较多。

2.priority
(数字),可选参数,指明指令的优先级,若在单个DOM上有多个指令,则优先级高的先执行;

3.terminal
(布尔型),可选参数,可以被设置为true或false,若设置为true,则优先级低于此指令的其他指令则无效,不会被调用(优先级相同的还是会执行)

4.template(字符串或者函数)可选参数,可以是:

(1)一段HTML文本

<!DOCTYPE html> 
<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> 
<body> 
<hello-world></hello-world> 
</body> 
<script type="text/javascript"> 
var app = angular.module('myApp', []); 
app.directive('helloWorld', function() { 
 return { 
 restrict: 'E', 
 template: '<div><h1>Hi 我是林炳文~~~</h1></div>', 
 replace: true 
 }; 
}); 
</script> 
</html> 

2)一个函数,可接受两个参数tElement和tAttrs
其中tElement是指使用此指令的元素,而tAttrs则实例的属性,它是一个由元素上所有的属性组成的集合(对象)形如:
<hello-world2 title = '我是第二个directive'></hello-world2>  
其中title就是tattrs上的属性

下面让我们看看template是一个函数时候的情况

<!DOCTYPE html> 
<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> 
<body> 
<hello-world></hello-world> 
<hello-world2 title = '我是第二个directive'></hello-world2> 
</body> 
<script type="text/javascript"> 
var app = angular.module('myApp', []); 
app.directive('helloWorld', function() { 
 return { 
 restrict: 'E', 
 template: '<div><h1>Hi 我是林炳文~~~</h1></div>', 
 replace: true 
 }; 
}); 
app.directive("helloWorld2",function(){ 
 return{ 
 restrict:'EAC', 
 template: function(tElement,tAttrs){ 
 var _html = ''; 
 _html += '<div>' +'hello '+tAttrs.title+'</div>'; 
 return _html; 
 } 
 }; 
 }); 
</script> 
</html> 

可以看到指令中还用到了hello-world2中的标签中的 title字段

5.templateUrl(字符串或者函数),可选参数,可以是

(1)一个代表HTML文件路径的字符串

(2)一个函数,可接受两个参数tElement和tAttrs(大致同上)

注意:在本地开发时候,需要运行一个服务器,不然使用templateUrl会报错 Cross Origin Request Script(CORS)错误。由于加载html模板是通过异步加载的,若加载大量的模板会拖慢网站的速度,这里有个技巧,就是先缓存模板

你可以再你的index页面加载好的,将下列代码作为你页面的一部分包含在里面。

<script type='text/ng-template' id='hello.html'> 
 <div><h1>Hi 我是林炳文~~~</h1></div> 
</script> 

这里的id属性就是被设置在templateUrl上用的。

<!DOCTYPE html> 
<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> 
<body> 
<hello-world></hello-world> 
</body> 
<script type="text/javascript"> 
var app = angular.module('myApp', []); 
app.directive('helloWorld', function() { 
 return { 
 restrict: 'E', 
 templateUrl: 'hello.html', 
 replace: true 
 }; 
}); 
</script> 
<script type='text/ng-template' id='hello.html'> 
 <div><h1>Hi 我是林炳文~~~</h1></div> 
</script> 
</html> 

另一种办法缓存是:

app.run(["$templateCache", function($templateCache) { 
 $templateCache.put("hello.html", 
 "<div><h1>Hi 我是林炳文~~~</h1></div>"); 
}]); 

使用实例如下:

<!DOCTYPE html> 
<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> 
<body> 
<hello-world></hello-world> 
</body> 
<script type="text/javascript"> 
var app = angular.module('myApp', []); 
app.directive('helloWorld', function() { 
 return { 
 restrict: 'E', 
 templateUrl: 'hello.html', 
 replace: true 
 }; 
}); 
app.run(["$templateCache", function($templateCache) { 
 $templateCache.put("hello.html", 
 "<div><h1>Hi 我是林炳文~~~</h1></div>"); 
}]); 
</script> 
</html> 

结果为:

其实第一种方法还好一些,写起来会比较快,笔者就得最多的也是第一种写法,直接包在scprit当中

 6.replace

(布尔值),默认值为false,设置为true时候,我们再来看看下面的例子(对比下在template时候举的例子)

replace为true时,hello-world这个标签不在了,反之,则存在。

7.scope

(1)默认值false。表示继承父作用域;

(2)true。表示继承父作用域,并创建自己的作用域(子作用域);

(3){}。表示创建一个全新的隔离作用域;

7.1首先我们先来了解下scope的继承机制。我们用ng-controller这个指令举例,

<!DOCTYPE html> 
<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> 
<body> 
<div ng-controller='MainController'> 
 父亲:{{name}}<input ng-model="name" /> 
 <div my-directive></div> 
 </div> 
</body> 
<script type="text/javascript"> 
var app = angular.module('myApp', []); 
app.controller('MainController', function ($scope) { 
 $scope.name = '林炳文'; 
}); 
app.directive('myDirective', function () { 
 return { 
 restrict: 'EA', 
 scope:false, 
 template: '<div>儿子:{{ name }}<input ng-model="name"/></div>' 
 }; 
}); 
</script> 
</html> 

接下来我们通过一个简单明了的例子来说明scope取值不同的差别:

scope:false

scope:true

scope:{}

当为false时候,儿子继承父亲的值,改变父亲的值,儿子的值也随之变化,反之亦如此。(继承不隔离)

当为true时候,儿子继承父亲的值,改变父亲的值,儿子的值随之变化,但是改变儿子的值,父亲的值不变。(继承隔离)

当为{}时候,没有继承父亲的值,所以儿子的值为空,改变任何一方的值均不能影响另一方的值。(不继承隔离)

 

指令的内容比较多,下面再来讲讲transclude、compline、link、contrller

8.transclude

如果不想让指令内部的内容被模板替换,可以设置这个值为true。一般情况下需要和ngTransclude指令一起使用。 比如:template:"<div>hello every <div ng-transclude></div></div>",这时,指令内部的内容会嵌入到ng-transclude这个div中。也就是变成了<div>hello every <div>这是指令内部的内容</div></div>。默认值为false;这个配置选项可以让我们提取包含在指令那个元素里面的内容,再将它放置在指令模板的特定位置。当你开启transclude后,你就可以使用ng-transclude来指明了应该在什么地方放置transcluded内容

<!DOCTYPE html> 
<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 link</li> 
  <li>Second link</li> 
  </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等等)
 
[html] view plain copy 在CODE上查看代码片派生到我的代码片
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链接函数只能在当前内部指令中定义行为,且无法再指令间复用。

<!DOCTYPE html> 
<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

11.require(字符串或者数组)

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。在实践中,编写自定义指令时这种操作是非常罕见的,但有几个内置指令提供了这样的功能。 链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义时,编译函数会重载链接函数。如果我们的指令很简单,并且不需要额外的设置,可以从工厂函数(回调函数)返回一个函数来代替对象。如果这样做了,这个函数就是链接函数。

 

 

 

原文来自:http://www.jb51.net/article/83051.htm

 

posted @ 2017-02-28 13:59  chenguiya  阅读(1128)  评论(0)    收藏  举报