angular自定义指令详解

Posted 指尖下的精灵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了angular自定义指令详解相关的知识,希望对你有一定的参考价值。

一、指令的创建:

首先你得先创建一个module:

 
   
   
 
  1. var module1 = angular.module('module1',[]);

  2. angular.bootstrap(document.body,['module1']);

然后你还得有一个对应的controller:
 
   
   
 
  1. var module1 = angular.module('module1',[]);

  2. module1.controller('ctl1', function($scope) {

  3.   $scope.content = 'i\'m, module 1';

  4.    $scope.name = 'module1';

  5.    $scope.save = function() {

  6.        console.log('is function save');

  7.    };

  8. });

  9. angular.bootstrap(document.body,['module1']);

然后你就可以安心的创建指令了:

 
   
   
 
  1. // 衔接上面的代码

  2. m1.directive('testDirective', function() {

  3.    // 将对象return出去

  4.    return{

  5.        restrict: 'E',// 指令类型  E:element A:attribute M:comment C: class

  6.        template: '<div>我是指令生成的内容</div>';

  7.        replace: true, //使用模板替换原始标记  指令内原本的数据将被清空

  8.    }

  9. });

  10. angular.bootstrap(document.body,['module1']);

对应的html可以这样写:

 
   
   
 
  1. <body>

  2.    <div  ng-controller="ctl1">{{content}}

  3.        <test-directive>这是原本的内容</test-directive>

  4.    </div>

  5. </body>

以上代码需要注意一下几点:

1.我们定义的指令名称是testDirective,但是在html中要写成test-directive。 2.我们把指令里面的代码都放在了function中的return里面,其实return出去的内容就是整个指令对象。 3.angular.bootstrap(document.body,['module1']);相当于我们在html中使用ng-app指令。推荐使用bootstarp而不是ng-app;

二、指令的属性

指令的属性如下:

1、name 2、priority 3、terminal 4、scope 5、controller 6、require 7、restrict 8、template 9、templateUrl 10、replace 11、transclude 12、compile 13、link

name就是指令名,对应上面代码中的testDirective,priority多个指令设置在同一个元素上的执行优先级,执行顺序从低至高:1>2>3.priority的值为正整数,比如priority: 1, terminal, true/false 如果为true,同一个元素上的其他指令的优先级高于本指令,其他指令将停止执行。

1.restrict属性

angular内置的一些指令,比如ng-app,ng-click之类的,都是以html元素的属性(atrrbile)的形式来实现的,我在使用ionic框架的时候,里面有很多自定义的标签、比如: 。这也是一个指令,他是通过html元素(element)来实现的。除了这两个之外,指令还支持class(html标签的class属性)、commment(html中的注释)来实现。

在JS代码中,restrict可以有以下赋值:

 
   
   
 
  1. restrict: 'AE',// 指令类型  E:element A:attribute M:comment C: class

可以是多个restrict: 'AEMC',也可以是一个restrict: 'E'。在html中对应的写法为:

其中注释: <!-- 两边一定要留空格,不然什么都不会发生 -->

2.template和templateUrl

同一个指令中只能template和templateUrl只能选其一。 template为模板内容。即你要在指令所在的容器中插入的html代码。

template属性接收一个字符串,类似这样:

 
   
   
 
  1.  template: '<div>我是指令生成的内容</div>';

你也可以将整个template写得很复杂,但是,复杂的代码非常不易维护。并且你还得换行,得用字符串拼接每一行。 当你的tamplate超出10行就会显得辣眼睛,过长的template建议使用templateUrl代替。

3.replace和transclude

replace:是否用模板替换当前元素。true : 将指令标签替换成temple中定义的内容,页面上不会再有 标签;false :则append(追加)在当前元素上,即模板的内容包在 标签内部。默认false。 transculde:是否使用ng-transculde来包含html中指令包含的原有的内容,接收两个参数true/false

先上例子:replace

 
   
   
 
  1. var app = angular.module("app", [])

  2.    .directive("hello", function () {

  3.        var option = {

  4.            restrict: "AECM",

  5.            template: "<h3>Hello, Directive</h3>",

  6.            replace: true  //这里replace为true,所以原来的内容会被template代替

  7.        };

  8.        return option;

  9.    })

 
   
   
 
  1. <html>

  2.    <head></head>

  3.    <body>

  4.        <hello>我是原来的内容</hello> ===> 变成<h3>Hello, Directive</h3>

  5.       如果replacefalse ===><hello><h3>Hello, Directive</h3></hello>

  6. </body>

  7. </html>

transclude:

 
   
   
 
  1. var app = angular.module("app", [])

  2.    .directive("hello", function () {

  3.        var option = {

  4.            restrict: "AECM",

  5.            template: "<h3>Hello, Directive</h3><span ng-transclude></span>",

  6.            transculde: true  //这里transculde为true,所以原来的内容会被放在有ng-transclude属性的标签内

  7.        };

  8.        return option;

  9.    })

 
   
   
 
  1. <html>

  2.    <head></head>

  3.    <body>

  4.        <hello>我是原来的内容</hello> ===> 变成<hello><h3>Hello, Directive</h3><span ng-transclude>我是原来的内容</span></hello>

  5. </body>

  6. </html>

4.指令中的scope

directive 默认能共享父 scope 中定义的属性,例如在模版中直接使用父 scope 中的对象和属性。通常使用这种直接共享的方式可以实现一些简单的 directive 功能。 但是,当你要创建一个可以重复使用的directive的时候,就不能依赖于父scope了,因为在不同的地方使用directive对应的父scope不一样。 所以你需要一个隔离的scope,我们可以向下面这样来定义我们的scope。

 
   
   
 
  1. module1.directive("testDirective", function () {

  2.        return {

  3.            scope: {

  4.                value: '提莫队长正在待命!'

  5.                         },

  6.            template: 'Say:{{value}}'

  7.        }

  8. });

这样就很方便的将我们directive的上下文scope给定义出来了,但是,如果我想将父scope中的属性传递给directive的scope怎么办呢? directive 在使用隔离 scope 的时候,提供了三种方法同隔离之外的地方交互:

1、@ 绑定一个局部 scope 属性到当前 dom 节点的属性值。结果总是一个字符串,因为 dom 属性是字符串。 2、& 提供一种方式执行一个表达式在父 scope 的上下文中。如果没有指定 attr 名称,则属性名称为相同的本地名称。 3、= 通过 directive 的 attr 属性的值在局部 scope 的属性和父 scope 属性名之间建立双向绑定。

以上三种方式都要在directive的attr属性中进行赋值。上面的话理解起来比较困难,我根据自己的理解做了一下修改。

1、@:只能绑定字符串,所以一些简单的继承父scope的属性使用@ 2、=: 需要实现双向数据绑定的时候使用= 3、&: 提供一种方式执行一个表达式在父scope的上下文中,即使用于将父scope中的函数绑定在指令的scope中

以上的理解也许有些偏颇,欢迎指正。 (1)先说@

 
   
   
 
  1. app.controller("ctl1", function ($scope) {

  2.        $scope.name = "hello world";

  3.    }).directive("testDirective", function () {

  4.        return {

  5.            scope: {

  6.                name: "@"

  7.            },

  8.            template: 'Say:{{name}} <br>改变隔离scope的name:<input type="buttom" value="" ng-model="name" class="ng-pristine ng-valid">'

  9.        }

  10. })

 
   
   
 
  1. <div ng-controller="ctl1">

  2.   <div>

  3.       <div>父scope

  4.           <div>Say:{{name}}<br>改变父scopename:<input type="text" value="" ng-model="name"/></div>

  5.       </div>

  6.       <div>隔离scope:这个显示为hello world

  7.           <div test-directive name="{{name}}"></div>

  8.       </div>

  9.        <div>隔离scope(不使用{{name}}这个就直接显示为name了):

  10.             <div test-directive name="name"></div>

  11.         </div>

  12.   </div>

我们在test-directive指令所在的div上面,增加了一个name属性,要使用双花括号来给属性赋值。也可以写成nameCopy:'@nameForCtl',这样写,在给directive中的scope的属性赋值的时候,获取查询@后面的name这个标识对应的属性的值(这里nameForCtl在js中是驼峰写法,同样的在html中对应的属性名应该写成name-for-ctl)。 (2)=

上一个例子中,我们使用name="{{name}}"的形式来传递父scope 的属性对应的值,so,我们只是把对应的值传递给了directive的scope,当我想实现在directive中改变父scope传递过来的值时,父scope中的值也对应的改变,显然用@这种方法走不通。 这时=就派上用场了。

 
   
   
 
  1. app.controller("ctl1", function ($scope) {

  2.        $scope.user = {

  3.            name: 'hello',

  4.            id: 1

  5.        };

  6.    }).directive("testDirective", function () {

  7.        return {

  8.            scope: {

  9.                user: "="

  10.            },

  11.            template: 'Say:{{user.name}} <br>改变隔离scope的name:<input type="buttom" value="" ng-model="user.name"/>'

  12.        }

  13.    })

 
   
   
 
  1. <div ng-controller="ctl1">

  2.    <div>父scope

  3.        <div>Say:{{user.name}}<br>改变父scopename:<input type="text" value="" ng-model="user.name"/></div>

  4.    </div>

  5.    <div>隔离scope

  6.        <div isolated-directive user="user"></div>

  7.    </div>

  8.    <div>隔离scope(使用{{name}},这个会报错):

  9.        <div isolated-directive user="{{user}}"></div>

  10.    </div>

  11. </div>

这一个例子和上一个例子不同的地方就是属性赋值的时候,一个应该使用{{}},一个不该使用。=为了实现双向数据绑定,angular会使用‘=’对应的属性的值与父scope中的属性进行匹配,然后传递给diractive中的scope。 (3)&

& 方式提供一种途经使directive 能在父 scope 的上下文中执行一个表达式。此表达式可以是一个 function。其实说白了,就是可以使用在父scope中定义的函数。 比如:当你写了一个 directive,当用户点击按钮时,directive 想要通知 controller,controller 无法知道 directive 中发生了什么,也许你可以通过使用 angular 中的 event 广播来做到,但是必须要在 controller 中增加一个事件监听方法。 最好的方法就是让 directive 可以通过一个父 scope 中的 function,当 directive 中有什么动作需要更新到父 scope 中的时候,可以在父 scope 上下文中执行一段代码或者一个函数。

 
   
   
 
  1. app.controller("ctl1", function ($scope) {

  2.        $scope.value = "hello world";

  3.        $scope.click = function () {

  4.            $scope.value = Math.random();

  5.        };

  6.    }).directive("testDirective", function () {

  7.        return {

  8.            scope: {

  9.                action: "&"

  10.            },

  11.            template: '<input type="button" value="在directive中执行父scope定义的方法" ng-click="action()"/>'

  12.        }

  13.    })

 
   
   
 
  1. <div  ng-controller="ctl1">

  2.        <div>父scope

  3.            <div>Say:{{value}}</div>

  4.        </div>

  5.        <div>隔离scope

  6.            <div isolated-directive action="click()"></div>

  7.        </div>

  8. </div>

在上面的例子中,我们的属性action赋值为一个方法:action="click()",这样一写,一眼就看出来是个什么东西了,好像也没什么好解释的。


以上是关于angular自定义指令详解的主要内容,如果未能解决你的问题,请参考以下文章

day3 自定义指令详解

angular指令详解--自定义指令

angular的自定义指令---详解

angular自定义指令详解

angular 啥时候用服务啥时候用指令

Angular JS 中 指令详解