详说Angular之指令(directive)

前言

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

话题

restrict以及replace

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

.directive(‘‘, [‘‘, function(){
        // Runs during compile
        return {
            // name: ‘‘,
            // priority: 1,
            // terminal: true,
            // scope: {}, // {} = isolate, true = child, false/undefined = no change
            // controller: function($scope, $element, $attrs, $transclude) {},
            // require: ‘ngModel‘, // Array = multiple requires, ? = optional, ^ = check parent elements
            // restrict: ‘A‘, // E = Element, A = Attribute, C = Class, M = Comment
            // template: ‘‘,
            // templateUrl: ‘‘,
            // replace: true,
            // transclude: true,
            // compile: function(tElement, tAttrs, function transclude(function(scope, cloneLinkingFn){ return function linking(scope, elm, attrs){}})),
            link: function($scope, iElm, iAttrs, controller) {

            }
        };
    }]);

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

【1】脚本:

    var app = angular.module(‘app‘, []);
    app.directive("hello",function(){
        return{
            restrict:"EACM",
            template:"<h1>Hello</h1>"
        }
    });

【2】html:

    <hello></hello>
    <div hello></div>
    <p class="hello"></p>
    <!-- directive:hello -->

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

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

transclude

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

【脚本】:

    var app = angular.module(‘app‘, []);
    app.directive("hello",function(){
        return{
            restrict:"EACM",
            transclude:true,
            template:"<h1>Hello<div ng-transclude></div></h1>",
        }
    });

【html】:

    <hello>
        <div>博客园,你好</div>
    </hello>

结果如下:

tepmlateUrl

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

【脚本】:

    var app = angular.module(‘app‘, []);
    app.run(function($templateCache){
        $templateCache.put("hello.html","<h1>hello cnblogs</h1>")
    });
    app.directive("hello",function($templateCache){
        return{
            restrict:"AE",
            template:$templateCache.get("hello.html"),
            replace:true
        };
    });

【html】:

<hello></hello>

结果如下:

scope

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

【脚本】:

    var app = angular.module(‘app‘, []);
    app.directive("hello",function(){
        return{
            restrict:"AE",
            template:‘<div><input type="text" ng-model="test"/>{{test}}</div>‘,
            replace:true
        };
    });

【html】:

    <hello></hello><br/>
    <hello></hello><br/>
    <hello></hello>

我们来瞧瞧结果:

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

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

require

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

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

【脚本】:

    var app = angular.module(‘app‘, []);
    app.controller("ctrl",["$scope",function($scope){
        $scope.win = function(){
            alert("你赢了");
        }
    }])
    app.directive("lay",function(){
        return{
            restrict:"AE",
            scope:true,
            template:‘<div>点击我,有惊喜哦</div>‘,
            replace:true,
            link:function(scope,elment,attr){
                elment.on("click",function(){
                    scope.win();
                })
            }
        };
    });

【html】:

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

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

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

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

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

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

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

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

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

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

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

【脚本】:

    var app = angular.module(‘app‘, []);
    app.directive(‘customdirective‘, function(){
        return {
            controller: function($scope, $element, $attrs, $transclude) {
                var self = this;
                $scope.count = 0;
                self.add = function(){
                    $scope.$apply(function(){
                        $scope.count++;
                    })
                }
            },
            restrict: ‘E‘,
        };
    }).directive(‘childirective‘, function(){
        return {
            require: ‘^customdirective‘,
            restrict: ‘E‘,
            template: ‘<button id="add">点击增加1</button>‘,
            replace: true,
            link: function($scope, iElm, iAttrs, controller) {
                angular.element(document.getElementById("add")).on("click",controller.add);
            }
        };
    })

【html】:

<customdirective>
    <div>次数:{{count}} </div>
    <br/>
    <childirective></childirective>
</customdirective>

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

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

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

【脚本】:

    var app = angular.module(‘app‘, []);

    app.controller("first",["$scope",function($scope){
        $scope.first = function(){
            alert("第一个控制器函数");
        }
    }])

    app.controller("second",["$scope",function($scope){
        $scope.second = function(){
            alert("第二个控制器函数");
        }
    }])

    app.directive(‘lay‘, function(){
        return{
              restrict:"AE",
              link:function(scope,element,attr){
                  element.on("click",function(){
                      scope.$apply(attr.loader);
                  })
              }
        };
    });

【html】:

<div ng-controller="first">
    <lay loader="first()">第一个控制器</lay>
</div>
<br/>
<div ng-controller="second">
    <lay loader="second()">第二个控制器</lay>
</div>

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

结语

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

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

【脚本】:

    var app = angular.module(‘app‘, []);
    app.controller(‘ctrl‘, function ($scope, $location, $rootScope) {
    })
    app.directive("parentDirective", function () {
    return {
        restrict: ‘A‘,
        require: [‘form‘],
        controller: function () {
            // nothing here
        },
        link: function (scope, ele, attrs, controllers) {
            var formCtrl = controllers[0];
        }
    };
    }).directive(‘input‘, function () {
    return {
        restrict: ‘E‘,
        priority: -1000,
        require: [‘^?parentDirective‘, ‘^?angularValidator‘],
        link: function (scope, elm, attr, ctrl) {
            if (!ctrl) {
                return;
            }  

            elm.on(‘focus‘, function () {
                elm.addClass(‘apply-focus‘);  

                scope.$apply(function () {
                    ctrl.hasFocus = true;
                });
            });  

            elm.on(‘blur‘, function () {
                elm.removeClass(‘apply-focus‘);
                elm.addClass(‘apply-visited‘);  

                scope.$apply(function () {
                    ctrl.hasFocus = true;
                    ctrl.hasVisited = true;  

                });
            });  

        }
    };
});  

【html】:

 <form  ng-controller="ctrl" novalidate angular-validator >
        <div class="gloabl-form-content">  

            <div class="row">
                <div class="col yellow-divider">
                    <div class="col-first">
                        <label><span  style="color:red;">*</span>姓名</label>
                    </div>
                    <div class="col-second">
                        <input name="name"
                            type="text"
                            ng-model="profile.name"
                            validate-on="blur"
                            ng-pattern="/^[ a-zA-Z]*$/"
                            required
                            required-message="‘请输入姓名.‘"
                            ng-message="‘不能输入数字‘"
                            maxlength="100" />
                    </div>  

                    <div class="col-third">
                        <label>住址</label>
                    </div>
                    <div class="col-four">
                        <input name="addr" type="text" ng-model="profile.addr"
                            validate-on="blur"
                            ng-pattern="/^[ a-zA-Z]*$/"
                            invalid-message="‘不能输入数字‘"
                            maxlength="100" />
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col yellow-divider">
                    <div class="col-third">
                        <label><span  style="color: red;">*</span>手机号码</label>
                    </div>
                    <div class="col-four">
                        <input type="text"
                            ng-model="customer.number"
                            validate-on="blur"
                            ng-pattern="/^[ 0-9.]*$/"
                            required
                            required-message="‘请输入手机号码‘"
                            invalid-message="‘只能输入数字‘" />
                    </div>
                </div>
            </div>  

        </div>
    </form>  

效果(1):

效果(2):

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

时间: 2025-01-07 10:01:54

详说Angular之指令(directive)的相关文章

Angular之指令Directive系列

项目筹备近期开启Angular学习,指令比较难理解所以记录备案,推荐视频大漠穷秋 Angular实战 由于篇幅过长,列举大纲如下: 一.指令directive概述 指令可以对元素绑定事件监听或者改变DOM结构而使HTML拥有像jQuery一样效果具有交互性.不同于jQuery,Angular设计核心思想是通过数据与模板的绑定,摆脱繁琐的DOM操作,而将注意力集中在业务逻辑上. 几种常见指令ng-app 指令用来指定ng的作用域是在那个标签以内部分(<html ng-app="myApp&q

angular 自定义指令 directive transclude 理解

项目中断断续续的用了下angular,也没狠下心 认真的学习.angular 特别是自定义指令这块 空白. transclude 定义是否将当前元素的内容转移到模板中.看解释有点抽象. 看解释有点抽象Demo: <!DOCTYPE html> <html lang="en" ng-app='myApp'> <head> <meta charset="UTF-8"> <title>Angularjs</

Angular JS (指令 directive)

一,指令的创建 /*--Js code--*/var app = angular.module("superhero",[]);app.directive("superman",function(){return { restrict: "E", template: "<div> Here I am to save the day </div>"}}) /*--HTML code--*/<div

angular 自定义指令详解 Directive

在angular中,Directive,自定义指令的学习,可以更好的理解angular指令的原理,当angular的指令不能满足你的需求的时候,嘿嘿,你就可以来看看这篇文章,自定义自己的指令,可以满足你的各种需求的指令. 本篇文章的参考来自  AngularJS权威指南 , 文章中主要介绍指令定义的选项配置 废话不多说,下面就直接上代码 //angular指令的定义,myDirective ,使用驼峰命名法 angular.module('myApp', []) .directive('myDi

Angular自定义指令(directive)

angular自定义指令,意我们可以通过angula自己定义指令,来实现我们的特殊要求,为所欲为,一支穿云箭,千军万马来相见 多少年的老规矩了,先看代码: 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content=&quo

-_-#【Angular】自定义指令directive

AngularJS学习笔记 <!DOCTYPE html> <html ng-app="Demo"> <head> <meta charset="utf-8"> <title></title> </head> <body> <script src="jquery-1.8.3.min.js"></script> <scrip

angularjs 一篇文章看懂自定义指令directive

 壹 ? 引 在angularjs开发中,指令的使用是无处无在的,我们习惯使用指令来拓展HTML:那么如何理解指令呢,你可以把它理解成在DOM元素上运行的函数,它可以帮助我们拓展DOM元素的功能.比如最常用ng-click可以让一个元素能监听click事件,这里你可能就有疑问了,同样都是监听为什么不直接使用click事件呢,angular提供的事件指令与传统指令有什么区别?我们来看一个例子: <body ng-controller="myCtrl as vm"> <d

AngularJs 指令directive之require

controller的用法分为两种情形,一种是require自定义的controller,由于自定义controller中的属性方法都由自己编 写,使用起来比较简单:另一种方法则是require AngularJS内建的指令,其中大部分时间需要require的都是ngModel这个指令. 在自定义Angular指令时,其中有一个叫做require的字段,这个字段的作用是用于指令之间的相互交流.举个简单的例子,假如我们现在需要编写两 个指令,在linking函数中有很多重合的方法,为了避免重复自己

angular自定义指令-1

1.angular指令感觉就相当于写一个组件,扩展html的语法,比如你写了一个图片上产的组件input-image,引用的时候直接用指令引 <input-image ng-model="image_url"></input-image> 用就好 2.如何写angular指令,主要就是调用directive方法api,方法内返回一个包装特定属性对象 3.angular指令开始compile结束link 4.从外部像指令传递数据,有叫绑定策略,传递数据的主要有两种