创建angular自定义指令

——本文转自他处,稍作修改,完全为了方便自己理解,如有侵犯,请告知。


指令(Directives)是所有AngularJS应用最重要的部分。尽管AngularJS已经提供了非常丰富的指令,但还是经常需要创建应用特定的指令。

一个Angular指令可以有以下的四种表现形式: 

1. 一个新的HTML元素(<data-picker></data-picker>) (A)

2. 元素的属性(<input type=”text” data-picker/>) (E)

3. CSS class(<input type=”text” class=”data-picker”/>) (C)

4. 注释(<!–directive:data-picker –>) (M)

当然,我们可以控制我们的指令在HTML中的表现形式。下面我们来看一下AngularJS中的一个典型的指令的写法。指令注册的方式与 controller 一样,但是它返回的是一个拥有指令配置属性的简单对象(指令定义对象) 。

首先,创建一个指令:

var app = angular.module('myapp', []);
app.directive('helloWorld', function() {
  return {
      restrict: 'AE',
      replace: 'true',
      template: '<h1>Hello World!!</h1>'
  };
});
通过指令定义的元素属性(A)和标签属性(E)来使用该指令:

元素属性使用:

<hello-world/>或<hello:world/>
标签属性使用:

<div hello-world></div>或<div hello:world/>
通过上面的例子,我们看到restrict设置为AE,其意如上所说,共有四种定义,分别为A,E,C,M;

还有replace设置为true代表着生成的HTML内容是会替换掉定义此指令的HTML元素,即

<hello-world/>或<hello:world/>、<div hello-world></div>或<div hello:world/>
如果为false,则默认值,生成的模板会被插入到元素中去;

还有templat:这个属性规定了指令被Angular编译和链接(link)后生成的HTML标记。这个属性值不一定要是简单的字符串。template 可以非常复杂,而且经常包含其他的指令,以及表达式({{ }})等。更多的情况下你可能会见到 templateUrl, 而不是 template。所以,理想情况下,你应该将模板放到一个特定的HTML文件中,然后将 templateUrl 属性指向它。


link和scope

如上模板并没有太大意义,一般我们会在特定的scope下编译。默认情况下,指令并不会创建新的子scope。默认情况下它使用父scope。也就是说,如果指令存在于一个controller下,它就会使用这个controller的scope。 如何运用scope,我们要用到一个叫做 link 的函数。它由指令定义对象中的link属性配置。我们来改变一下我们的 helloWorld 指令,当用户在一个输入框中输入一种颜色的名称时,Hello World 文字的背景色自动发生变化。同时,当用户在 Hello World 文字上点击时,背景色变回白色。 相应的HTML标记如下:
<body ng-controller="myController">
  <input type="text" ng-model="color" />
  <hello-world/>
</body>
app.directive('helloWorld', function() {
  return {
    restrict: 'AE',
    replace: true,
    template: '<p style="background-color:{{color}}">Hello World',
    link: function(scope, elem, attrs) {
      elem.bind('click', function() {
        elem.css('background-color', 'white');
        scope.$apply(function() {
          scope.color = "white";
        });
      });
      elem.bind('mouseover', function() {
        elem.css('cursor', 'pointer');
      });
    }
  };
});
以上link函数有三个参数:
scope:指令的scope,例子中的scope为父Controller的scope;
elem:指令的DOM。该DOM为jQuery包装过的,所以可以通过jQuery来操作;
attrs:一个包含了指令所在元素的属性的标准化的参数对象;(理解的有点模糊)

link函数主要用来为DOM元素添加事件监听、监视模型属性变化、以及更新DOM。在上面的指令代码片段中,我们添加了两个事件, click,和 mouseover。click 处理函数用来重置 <p> 的背景色,而 mouseover 处理函数改变鼠标为 pointer。在模板中有一个表达式 {{color}},当父scope中的 color 发生变化时,它用来改变 Hello World 文字的背景色。

compile函数

compile 函数在 link 函数被执行之前用来做一些DOM改造。它接收下面的参数:
1、 tElement – 指令所在的元素
2
attrs – 元素上赋予的参数的标准化列表

要注意的是 compile 函数不能访问 scope,并且必须返回一个 link 函数。但是如果没有设置 compile 函数,你可以正常地配置 link 函数,(有了compile,就不能用link,link函数由compile返回)。compile函数可以写成如下的形式:
app.directive('myDirective', function() {
  return {
    compile: function(tElem,attrs) {
      return function(scope,elem,attrs) {
        
      };
    }
  };
});
多数情况下我们只用到link函数,这是因为大部分的指令只需要考虑注册事件监听、监视模型、以及更新DOM等,这些都可以在 link 函数中完成。

改变指令的scope

默认情况下,指令获取它父节点的controller的scope。但这并不适用于所有情况。如果将父controller的scope暴露给指令,那么他们可以随意地修改 scope 的属性。在某些情况下,你的指令希望能够添加一些仅限内部使用的属性和方法。如果我们在父的scope中添加,会污染父scope。 其实我们还有两种选择:
1、子scope :这个scope原型继承子父scope。
2、隔离的scope –:孤立存在不继承自父scope的scope。

这样的scope可以通过指令定义对象中 scope 属性来配置:
继承父scope的子scope:
app.directive('helloWorld', function() {
  return {
    scope: true, 
    restrict: 'AE',
    replace: 'true',
    template: '<h3>Hello World!!</h3>'
  };
});

隔离的scope:
app.directive('helloWorld', function() {
  return {
    scope: {}, 
    restrict: 'AE',
    replace: 'true',
    template: '<h3>Hello World!!</h3>'
  };
});

通过隔离scope,我们可以创建重用的指令非常有好处, 我们能够保证我们的指令是自包含的,可以被很容易的插入到HTML应用中。 它内部不能访问父的scope,所保证了父scope不被污染。

隔离scope和父scope之间的数据绑定

隔离指令的scope会带来很多的便利,尤其是在你要操作多个scope模型的时候。但有时为了使代码能够正确工作,你也需要从指令内部访问父scope的属性。

选择一:使用 @ 实现单向文本绑定

在下面的指令定义中,我们指定了隔离scope中的属性 color 绑定到指令所在HTML元素上的参数 colorAttr。在HTML标记中,你可以看到 {{color}}表达式被指定给了 color-attr 参数。当表达式的值发生改变时,color-attr 参数也跟着改变。隔离scope中的 color 属性的值也相应地被改变。
app.directive('helloWorld', function() {
  return {
    scope: {
      color: '@colorAttr'
    },
    ....
  };
});
<body ng-controller="MainCtrl">
  <input type="text" ng-model="color" />
  <hello-world color-attr="{{color}}"/>
</body>
注意点:
当隔离scope属性和指令元素参数的名字一样时,我们可以更简单的方式设置scope绑定:
app.directive('helloWorld', function() {
  return {
    scope: {
      color: '@'
    },
    ....
  };
});
<hello-world color="{{color}}"/>

选择二:使用 = 实现双向绑定

我们把指令的定义改变成下面的样子:
app.directive('helloWorld', function() {
  return {
    scope: {
      color: '='
    },
    ....
  };
});
<body ng-controller="MainCtrl">
  <input type="text" ng-model="color" />
  <hello-world color="color"/>
</body>
与 @ 不同,这种方式让你能够给属性指定一个真实的scope数据模型,而不是简单的字符串。这样你就可以传递简单的字符串、数组、甚至复杂的对象给隔离scope。同时,还支持双向的绑定。每当父scope属性变化时,相对应的隔离scope中的属性也跟着改变,反之亦然。和之前的一样,你也可以监视这个scope属性的变化。

选择三:使用 & 在父scope中执行函数

有时候从隔离scope中调用父scope中定义的函数是非常有必要的。为了能够访问外部scope中定义的函数,我们使用 &。比如我们想要从指令内部调用 sayHello() 方法。
app.directive('sayHello', function() {
  return {
    scope: {
      sayHelloIsolated: '&'
    },
    ....
  };
});
<body ng-controller="MainCtrl">
  <input type="text" ng-model="color" />
  <say-hello sayHelloIsolated="sayHello()"/>
</body>










  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值