前言

angular核心部分如下图几大块,最重要的莫过于指令这一部分,本文将重点讲解指令这一部分,后续笔者将通过陆续的学习来叙述其他如:factory、service等,若有叙述错误之处,欢迎各位指正以及批评。本文将通过一些实例来进行叙述。

话题

restrict以及replace

在sublimeText中安装angular插件之后,我们需要创建指令时此时将自动出现如下定义:所以我们将重点放在如下各个变量的定义。

  1. .directive('', ['', function(){
  2. // Runs during compile
  3. return {
  4. // name: '',
  5. // priority: 1,
  6. // terminal: true,
  7. // scope: {}, // {} = isolate, true = child, false/undefined = no change
  8. // controller: function($scope, $element, $attrs, $transclude) {},
  9. // require: 'ngModel', // Array = multiple requires, ? = optional, ^ = check parent elements
  10. // restrict: 'A', // E = Element, A = Attribute, C = Class, M = Comment
  11. // template: '',
  12. // templateUrl: '',
  13. // replace: true,
  14. // transclude: true,
  15. // compile: function(tElement, tAttrs, function transclude(function(scope, cloneLinkingFn){ return function linking(scope, elm, attrs){}})),
  16. link: function($scope, iElm, iAttrs, controller) {
  17.  
  18. }
  19. };
  20. }]);

首先我们只需要知道一个属性【restrict】,意思是替换的是什么,【E】:元素,【A】:属性,【C】:类名,【M】:注释。template(模板)自然就不用说了。下面我们来看一个有关指令最简单的例子。

【1】脚本:

  1. var app = angular.module('app', []);
  2. app.directive("hello",function(){
  3. return{
  4. restrict:"EACM",
  5. template:"<h1>Hello</h1>"
  6. }
  7. });

【2】html:

  1. <hello></hello>
  2. <div hello></div>
  3. <p class="hello"></p>
  4. <!-- directive:hello -->

此时的结果是四个带h1标签的Hello吗?显然不是,如下:

不是说好的将restrict的模式设置为【EACM】,理论上应该是显示四个,结果却不是。即使你设置了四个也只会显示三个,而注释不会显示,此时要设置另外一个属性即【replace:true】才会显示四个注释。同时也需要注意,在注释中的hello和后面的--之间要有间隔,你可以试试。

transclude

当我们替换的元素里面可能还嵌套者其他元素,而其他元素里面有内容,我们不希望被覆盖,此时就需要将transclude设置为true并将要应用的元素标记为ng-transclude。如下:

【脚本】:

  1. var app = angular.module('app', []);
  2. app.directive("hello",function(){
  3. return{
  4. restrict:"EACM",
  5. transclude:true,
  6. template:"<h1>Hello<div ng-transclude></div></h1>",
  7. }
  8. });

【html】:

  1. <hello>
  2. <div>博客园,你好</div>
  3. </hello>

结果如下:

tepmlateUrl

在实际开发中用template形式来给出模板似乎不太友好,一旦替换的内容比较多那么显得代码比较凌乱,此时我们就要用到templateUrl,将模板单独写在一个页面即可。这个就不用说了,在这个内容不得不说的是模板的缓存。

【脚本】:

  1. var app = angular.module('app', []);
  2. app.run(function($templateCache){
  3. $templateCache.put("hello.html","<h1>hello cnblogs</h1>")
  4. });
  5. app.directive("hello",function($templateCache){
  6. return{
  7. restrict:"AE",
  8. template:$templateCache.get("hello.html"),
  9. replace:true
  10. };
  11. });

【html】:

  1. <hello></hello>

结果如下:

scope

在接触这个属性之前我们首先来看看一个例子。

【脚本】:

  1. var app = angular.module('app', []);
  2. app.directive("hello",function(){
  3. return{
  4. restrict:"AE",
  5. template:'<div><input type="text" ng-model="test"/>{{test}}</div>',
  6. replace:true
  7. };
  8. });

【html】:

  1. <hello></hello><br/>
  2. <hello></hello><br/>
  3. <hello></hello>

我们来瞧瞧结果:

我们将鼠标放在第一个文本框输入xpy0928,下面两个同样也发生相应的改变,我们再试试将鼠标聚焦于第二个看看其他两个的改变如何:

由上知,同样如此,貌似三个文本框的作用域是一样的,一变都变,相互影响。在指令中,当我们需要保持各自的作用域时,此时就需要【scope】属性,并设置为true。我们再来试试

require

【指令与页面上已定义控制器进行交互】

在开始这个话题之前我们先看看指令与已定义的控制器如何进行交互?【注意是在页面上已定义的控制器】

【脚本】:

  1. var app = angular.module('app', []);
  2. app.controller("ctrl",["$scope",function($scope){
  3. $scope.win = function(){
  4. alert("你赢了");
  5. }
  6. }])
  7. app.directive("lay",function(){
  8. return{
  9. restrict:"AE",
  10. scope:true,
  11. template:'<div>点击我,有惊喜哦</div>',
  12. replace:true,
  13. link:function(scope,elment,attr){
  14. elment.on("click",function(){
  15. scope.win();
  16. })
  17. }
  18. };
  19. });

【html】:

  1. <div ng-controller="ctrl" style="background-color:orange">
  2. <lay></lay>
  3. </div>

对于页面中已定义的控制器,指令为与其进行交互直接通过link上的scope来获取该控制器上的APi即可。

【指令与指令上控制器进行交互】

此时就需要用到require,此属性的作用是指令与指令之间的交互,说的更加具体一点就是与其他指令中控制器之间的交互。在指令中获取其他指令的控制器要用到link函数的第四个参数,link函数的前三个参数还是非常容易理解,不再叙述。那么是怎样在当前指令去获取该控制器呢?这时就需要用到require属性。

(1)require的值用?、^、或者?^修饰。

(2)如果不用任何修饰,则在当前指令中进行查找控制器。

(3)如果用^修饰,则在当前指令的父指令进行查找控制器,若未找到,则会抛出异常。

(4)如果用?修饰,则说明在当前指令中未找到控制器,此时将以null作为第四个参数。

(5)如果需要交互多个指令,则以数组形式给出,如:[^?a,^?b]。

鉴于此,为了不抛出异常,我们一般以^?来进行修饰。

就上面解释,我们来看一个例子,如下:

【脚本】:

  1. var app = angular.module('app', []);
  2. app.directive('customdirective', function(){
  3. return {
  4. controller: function($scope, $element, $attrs, $transclude) {
  5. var self = this;
  6. $scope.count = 0;
  7. self.add = function(){
  8. $scope.$apply(function(){
  9. $scope.count++;
  10. })
  11. }
  12. },
  13. restrict: 'E',
  14. };
  15. }).directive('childirective', function(){
  16. return {
  17. require: '^customdirective',
  18. restrict: 'E',
  19. template: '<button id="add">点击增加1</button>',
  20. replace: true,
  21. link: function($scope, iElm, iAttrs, controller) {
  22. angular.element(document.getElementById("add")).on("click",controller.add);
  23. }
  24. };
  25. })

【html】:

  1. <customdirective>
  2. <div>次数:{{count}} </div>
  3. <br/>
  4. <childirective></childirective>
  5. </customdirective>

对于指令上的link与指令上的controller的何时使用,我们可以这样概括:当一个指令上想向外部暴露这个指令时,此时利用controller进行暴露,而其他指令需要利用指令时,通过属性require和link上的第四个参数进行获取暴露指令的APi,否则的话我们不需要第四个参数。

那么问题来了,指令的作用到底是什么呢?

假如我们有几个控制器都需要用到相同指令但是对应不同事件时,此时难道需要定义不同的指令吗?答案肯定很显然不是,指令说到底就是为了【复用】。下面我们继续来看一个例子。

【脚本】:

  1. var app = angular.module('app', []);
  2.  
  3. app.controller("first",["$scope",function($scope){
  4. $scope.first = function(){
  5. alert("第一个控制器函数");
  6. }
  7. }])
  8.  
  9. app.controller("second",["$scope",function($scope){
  10. $scope.second = function(){
  11. alert("第二个控制器函数");
  12. }
  13. }])
  14.  
  15. app.directive('lay', function(){
  16. return{
  17. restrict:"AE",
  18. link:function(scope,element,attr){
  19. element.on("click",function(){
  20. scope.$apply(attr.loader);
  21. })
  22. }
  23. };
  24. });

【html】:

  1. <div ng-controller="first">
  2. <lay loader="first()">第一个控制器</lay>
  3. </div>
  4. <br/>
  5. <div ng-controller="second">
  6. <lay loader="second()">第二个控制器</lay>
  7. </div>

 当需要复用指令时,可以通过获取指令上属性对应的方法,最终利用apply方法应用到对应的控制器中。

结语

在这里我们稍微详细的叙述了指令中有关属性的用法,对于一些原理性的东西,毕竟不是做前端的,所以没有做过多的探讨。下面我们最后以一个实例来结束本文。

通过指令来使未验证通过的文本框聚焦。

【脚本】:

  1. var app = angular.module('app', []);
  2. app.controller('ctrl', function ($scope, $location, $rootScope) {
  3. })
  4. app.directive("parentDirective", function () {
  5. return {
  6. restrict: 'A',
  7. require: ['form'],
  8. controller: function () {
  9. // nothing here
  10. },
  11. link: function (scope, ele, attrs, controllers) {
  12. var formCtrl = controllers[0];
  13. }
  14. };
  15. }).directive('input', function () {
  16. return {
  17. restrict: 'E',
  18. priority: -1000,
  19. require: ['^?parentDirective', '^?angularValidator'],
  20. link: function (scope, elm, attr, ctrl) {
  21. if (!ctrl) {
  22. return;
  23. }
  24.  
  25. elm.on('focus', function () {
  26. elm.addClass('apply-focus');
  27.  
  28. scope.$apply(function () {
  29. ctrl.hasFocus = true;
  30. });
  31. });
  32.  
  33. elm.on('blur', function () {
  34. elm.removeClass('apply-focus');
  35. elm.addClass('apply-visited');
  36.  
  37. scope.$apply(function () {
  38. ctrl.hasFocus = true;
  39. ctrl.hasVisited = true;
  40.  
  41. });
  42. });
  43.  
  44. }
  45. };
  46. });

【html】:

  1. <form ng-controller="ctrl" novalidate angular-validator >
  2. <div class="gloabl-form-content">
  3.  
  4. <div class="row">
  5. <div class="col yellow-divider">
  6. <div class="col-first">
  7. <label><span style="color:red;">*</span>姓名</label>
  8. </div>
  9. <div class="col-second">
  10. <input name="name"
  11. type="text"
  12. ng-model="profile.name"
  13. validate-on="blur"
  14. ng-pattern="/^[ a-zA-Z]*$/"
  15. required
  16. required-message="'请输入姓名.'"
  17. ng-message="'不能输入数字'"
  18. maxlength="100" />
  19. </div>
  20.  
  21. <div class="col-third">
  22. <label>住址</label>
  23. </div>
  24. <div class="col-four">
  25. <input name="addr" type="text" ng-model="profile.addr"
  26. validate-on="blur"
  27. ng-pattern="/^[ a-zA-Z]*$/"
  28. invalid-message="'不能输入数字'"
  29. maxlength="100" />
  30. </div>
  31. </div>
  32. </div>
  33. <div class="row">
  34. <div class="col yellow-divider">
  35. <div class="col-third">
  36. <label><span style="color: red;">*</span>手机号码</label>
  37. </div>
  38. <div class="col-four">
  39. <input type="text"
  40. ng-model="customer.number"
  41. validate-on="blur"
  42. ng-pattern="/^[ 0-9.]*$/"
  43. required
  44. required-message="'请输入手机号码'"
  45. invalid-message="'只能输入数字'" />
  46. </div>
  47. </div>
  48. </div>
  49.  
  50. </div>
  51. </form>

效果(1):

效果(2):

【擦,不行,快冻成傻逼了,手冻僵了,不能写了,就到这里诺。。。。。。。。。。】

AngularJS之Directive(三)的更多相关文章

  1. angularJS中directive父子组件的数据交互

    angularJS中directive父子组件的数据交互 1. 使用共享 scope 的时候,可以直接从父 scope 中共享属性.使用隔离 scope 的时候,无法从父 scope 中共享属性.在 ...

  2. AngularJS之directive

    AngularJS之directive AngularJS是什么就不多舌了,这里简单介绍下directive.内容基本上是读书笔记,所以如果你看过<AngularJS up and runnin ...

  3. Angularjs之directive指令学习笔记(二)

    1.Directive的五个实例知道driective作用.其中字段restrict.template. replace.transclude.link用法 参考文章链接地址:http://damoq ...

  4. 前端angularJS利用directive实现移动端自定义软键盘的方法

    最近公司项目的需求上要求我们iPad项目上一些需要输入数字的地方用我们自定义的软键盘而不是移动端设备自带的键盘,刚接到需求有点懵,因为之前没有做过,后来理了一下思路发现这东西也就那样.先看一下实现之后 ...

  5. Angularjs的directive封装ztree

    一般我们做web开发都会用到树,恰好ztree为我们提供了多种风格的树插件. 接下来就看看怎么用Angularjs的directive封装ztree <!DOCTYPE html> < ...

  6. angularjs学习笔记三——directive

    AngularJS 通过被称为 指令 的新属性来扩展 HTML. 正如你所看到的,AngularJS 指令是以 ng 作为前缀的 HTML 属性. HTML5 允许扩展的(自制的)属性,以 data- ...

  7. AngularJS中Directive指令系列 - scope属性的使用

    文章是转的,我做下补充.原文地址:https://segmentfault.com/a/1190000002773689 每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部 ...

  8. 通过angularjs的directive以及service来实现的列表页加载排序分页

    前两篇:(列表页的动态条件搜索,我是如何做列表页的)分别介绍了我们是如何做后端业务系统数据展示类的列表页以及动态搜索的,那么还剩下最重要的一项:数据展示.数据展示一般包含三部分: 数据列头 数据行 分 ...

  9. 通过angularjs的directive以及service来实现的列表页加载排序分页(转)

    前两篇:(列表页的动态条件搜索,我是如何做列表页的)分别介绍了我们是如何做后端业务系统数据展示类的列表页以及动态搜索的,那么还剩下最重要的一项:数据展示.数据展示一般包含三部分: 数据列头 数据行 分 ...

随机推荐

  1. knockoutjs扩展与使用

    原来考虑使用avalon2.0 经过一周的试验,能力不够,用不起来.最终使用了knockout-3.4.js <!DOCTYPE html> <html> <head&g ...

  2. python使用pdkdf2加盐密码

    from werkzeug.security import generate_password_hash, check_password_hash pw = generate_password_has ...

  3. linux下tomcat安装

    1.先安装jdk,我们这里用yum进行安装: yum -y install java-1.7.0-openjdk* 确定是否安装成功: java -version 如果显示jdk的版本信息,说明安装成 ...

  4. Python 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)

    去空格及特殊符号 s.strip().lstrip().rstrip(',') 复制字符串 #strcpy(sStr1,sStr2) sStr1 = 'strcpy' sStr2 = sStr1 sS ...

  5. 用ProxyFactoryBean创建AOP代理

    Spring的Advisor是Pointcut和Advice的配置器,它是将Advice注入程序中Pointcut位置的代码.org.springframework.aop.support.Defau ...

  6. CentOS7 SWAP 设置 (实测 笔记)

    首先查看当前的内存及swap情况(参数 -h,-m ) [root@centos ~]# free -h 查看swap信息,包括文件和分区的详细信息 [root@centos ~]# swapon - ...

  7. System.Dynamic.ExpandoObject 类型的简单使用

    该类型可以实现的是动态添加属性和移除属性,有点类似 js 中对象的操作,非常灵活 static void Main(string[] args) { dynamic obj = new System. ...

  8. STL之deque

    deque是一种优化了的,对序列两段进行添加和删除操作的基本序列容器.它允许较为快速的随机访问,但它不像vector把所有对象保存在一块连续的内存块,而是采用多个连续的存储块.向deque两段添加或删 ...

  9. Lua游戏时区问题

    关于cocos2dx-lua版本中游戏时间显示问题 2015-04-19 19:07 1466人阅读 评论(0) 收藏 举报  分类: Lua(29)   cocos2d(38)  版权声明:本文为博 ...

  10. SDOI 2016 数字配对

    题目大意:给定n个数字以及每个数字的个数和权值,将满足条件的数字配对,使得总代价不小于0,且配对最多 最大费用最大流拆点,对于每个点,连一条由S到该点的边,容量为b,花费为0,再连一条到T的边 对于每 ...