前端框架——Angular.jsAngular.js专场angularjs

AngularJs directive

2016-06-24  本文已影响461人  菲汐

** "指令"是什么? **
指令是Angular中一个很重要的概念, 它是附加在HTML元素上的自定义标记, 在Angular官方文档中称之为HTML语言的DSL ( 特定领域语言 ) 扩展

根据指令的使用场景和作用可以分为组件型指令和装饰器型指令, 组件型的指令主要是为了将复杂的View分离, 使用View具有更强的可读性和维护性. 例如Tab, Accordion. 装饰器型的指令主要是为DOM添加行为, 例如ngShow, 让DOM具有条件显示的能力.

** 指令的匹配 **
我们在JS文件中定义了myDirective指令

angular.module('app',[]).directive('myDirective', function(){
})

我们如何在HTML上去使用这个指令?

<div my-directive></div>

除了这种最常见的方式之外, 你还可以通过下面这几种格式来匹配一个指令, 加上前缀更符合HTML5的规范.

<div data-my-directive></div>
<div x-my-directive></div>
<div my:directive></div>
<div my_directive></div>

Angular把一个元素的标签和属性名字规范化, 通常我们的指令采用小驼峰命名法, 比如ngModel. 然而HTML是不能区分大小写的, 所以我们无法在HTML上直接使用, 取而代之的是用破折号间隔的形式, 比如ng-model

规范化的过程如下

  1. 去掉元素或属性名字前面的x- 和 data-
  2. :, -, _转换成小驼峰命名法(camelCase)

** 创建指令 **
和控制器一样, 指令也是注册在模块上的. 要注册一个指令, 你可以用 module.directive API.
可以接受directiveName和directiveFactory两个参数注册单个指令, 也可以接受key/value形式的哈希对象, 注册多个指令, 这里的key对应directiveName, value对应directiveFactory.

myModule.directive('myDirective', function factory($log) {
    return {
        priority: 0,
        templateNamespace: 'html',
        template: '<div></div>',
        templateUrl: 'myDirective.html',
        replace: false,
        transclude: false,
        restrict: 'EACM',
        scope: false,
        require: '^anotherDirective',
        controller: function($scope){},
        controllerAs: 'vm', 
        bindToController: false,
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {...},
                post: function postLink(scope, iElement, iAttrs, controller) {...}
            }
        },
        link: function postLink(scope, iElement, iAttrs) {... }
    };
});

上面代码中的factory函数, 是"工厂函数", 它是用来创建指令的. 它只会被调用一次, 就是当编译器第一次匹配到相应指令的时候, 你可以在其中进行任何初始化的工作.
工厂函数返回的对象是"指令定义对象", 给编译器提供了生成指令需要的细节.

templateUrl: function(elem,attr){
    return 'template' + attr.name + '.html'
}
//index.html
<my-directive>
    Check out the contents!
</my-directive>
//myDirective.html
<div>
    <h1>directive transclude</h1>
    <span ng-transclude></span>
</div>

上面的代码会生成如下代码

<div>
    <h1>directive transclude</h1>
    <span>Check out the contents!</span>
</div>
//js
angular.module('app').controller('MyController', function(){
    var vm = this;
    vm.name = 'John Doe';
})
//template
<span ng-bind="vm.name"></span>

实际上你能猜到Angular在内部做了什么

if(directive.controllerAs){
    locals.$scope[directive.controllerAs] = controllerInstance;
}

** 改变指令的scope **
默认情况下, 指令获取它父节点的controller的scope. 但这并不适用于所有情况. 如果将父controller的scope暴露给指令, 那么他们可以随意地修改 scope 的属性. 在某些情况下, 你希望指令能够添加一些仅限内部使用的属性和方法. 那么你可以使用上一小节所说的true 或 哈希对象. 先看一个例子

//scope属性
{
  name: '@',
  detail: '=',
  job: '<',
  update: '&'  
}
//html
<my-directive name="John" detail="detail" age="age" update="update(times)">

接下来的这部分内容可能新手会比较难理解, 如果不适, 请稍作休息, 不要砸电脑. 上面的scope属性会为指令创建一个独立的作用域, 假设其为'A', 父级作用域为'B'

pscope.job= {
    title: 'myDetail',
    content: 'myContent'
}
B.update = function(times){
    //times can be any name you want
    return count + times;
}

我们还可以指定为一个可执行的表达式, 实际上就是一个Js语句. Angular会自动为我们创建一个函数包裹住这个执行表达式

update="count = count + 1"

使用须知,

\\scope
{
  name: '@whatever',
}
\\html
<my-directive whatever='John'>

如果我们的DOM不变, 但是我们scope定义为false, 也就是不使用独立作用域, 我们该如何获取这些属性的值?

** 指令的生命周期 **

myModule.directive('myDirective', function factory($log) {
    $log.info('...Injecting...');
    return {
        controller: function(){
            $log.info('...Controller...');
        },
        compile: function compile(tElement, tAttrs, transclude) {
            $log.info('...Compile...');
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {
                    $log.info('...Pre-Link...');
                },
                post: function postLink(scope, iElement, iAttrs, controller) {
                    $log.info('...Post-Link...');
                }
            }
        }
    };
});

Angular中, 一个指令从开始解析到生效, 按照顺序一共会经历Inject, Compile, Controller, Pre-Link, Post-Link几个过程.

更具体的关于这几个函数的介绍请参考ng.service.$compile

上一篇 下一篇

猜你喜欢

热点阅读