angularJS系列之指令directive应用实例

代码结构

这里写图片描述

html页面代码

<!DOCTYPE html>
<html ng-app="demoForDirective">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <script src="./lib/angular.js"></script>
    <script src="./js/app.js"></script>
    <script src="./js/controller.js"></script>
</head>
<body>
<div ng-controller='demoForDirectiveController'>
    <!--增加指令标签-->
    <testdirective testdirective-title='title'>
        {{text}}
    </testdirective>
</div>
<div>
    <!--为原生标签增加动态属性-->
    分数:<input type="text" attrsdirective/><br/>
</div>
<!--通过控制器控制子元素-->
<div ng-controller="SomeController">
    <accordion>
        <expander class="expander"
                  ng-repeat="expander in expanders"
                  expander-title="expander.title">
            {{expander.text}}
        </expander>
    </accordion>
</div>
</body>
</html>

app.js代码

/**
 * Created by jywl on 2016/7/7.
 */
var demoForDirective = angular.module('demoForDirective', ['demoForDirective.controller']);
demoForDirective.directive('testdirective', function () {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: {
            title: '=testdirectiveTitle'
        },
        template: '<div>'
        + '<div class="title" ng-click="toggle()">{{title}}</div>'
        + '<div class="body" ng-show="showMe" ng-transclude></div>'
        + '</div>',
        link: function (scope, element, attrs) {
            scope.showMe = false;
            scope.toggle = function toggle() {
                scope.showMe = !scope.showMe;
            }
        }
    }
});

demoForDirective.directive('attrsdirective', function () {
    return {
        link: function (scope, elements, attrs, controller) {
            elements[0].onkeyup = function () { //从元素列表中获取元素,并绑定相应的事件
                //下面的意思是,如果输入10以内的数,则输入框边框颜色不变,否则变为红色
                if (isNaN(this.value) || this.value < 1 || this.value > 10) {
                    this.style.borderColor = 'red';
                }
                else {
                    this.style.borderColor = '';
                }
            };
        }
    }
});

demoForDirective.directive('accordion', function () {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        template: '<div ng-transclude></div>',
        controller: function () { //声明一个内部的controller,用于传递值和方法
            var expanders = [];
            this.gotOpened = function (selectedExpander) {
                //angularJS的forEach用法
                /*var objs =[{a:1},{a:2}];
                 angular.forEach(objs, function(data,index,array){
                 //data等价于array[index]
                 console.log(data.a+'='+array[index].a);
                 });
                 参数如下:
                 objs:需要遍历的集合
                 data:遍历时当前的数据
                 index:遍历时当前索引
                 array:需要遍历的集合,每次遍历时都会把objs原样的传一次。
                * */
                angular.forEach(expanders, function (expander) {
                    if (selectedExpander != expander) {
                        expander.showMe = false;
                    }
                });
            }

            this.addExpander = function (expander) {
                expanders.push(expander);
            }
        }
    }
});

demoForDirective.directive('expander', function () {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        require: '^?accordion',//意思是将accordion的控制器传到指令中,从而在下方使用它的函数 ^的意思是需要遍历dom树,?的意思是找不到不报错
        scope: {
            title: '=expanderTitle'
        },
        template: '<div>'
        + '<div class="title" ng-click="toggle()">{{title}}</div>'
        + '<div class="body" ng-show="showMe" ng-transclude></div>'
        + '</div>',
        link: function (scope, element, attrs, accordionController) {
            scope.showMe = false;
            accordionController.addExpander(scope);

            scope.toggle = function toggle() {
                scope.showMe = !scope.showMe;
                accordionController.gotOpened(scope);
            }
        }
    }
});

controller.js代码

/**
 * Created by jywl on 2016/7/7.
 */
angular.module('demoForDirective.controller', [])
    .controller('demoForDirectiveController', function ($scope) {
        $scope.title = '点击展开';
        $scope.text = '这里是内部的内容。';
    })

    .controller('SomeController', function ($scope) {
        $scope.expanders = [
            {title: 'click me', text: 'one click'},
            {title: 'click me two', text: 'two click'},
            {title: 'click me three', text: 'three click'}];
    });

代码说明

主要详解app.js中关于指令的代码,大部分代码都有注释,如果还有不清楚的可以留言,我看到会及时回复的。

directive的参数说明

priority(优先级)- 当有多个directive定义在同一个DOM元素时,有时需要明确它们的执行顺序。这属性用于在directive的compile function调用之前进行排序。如果优先级相同,则执行顺序是不确定的(经初步试验,优先级高的先执行,同级时按照类似栈的“后绑定先执行”。另外,测试时有点不小心,在定义directive的时候,两次定义了一个相同名称的directive,但执行结果发现,两个compile或者link function都会执行)。据官方说,ng-repeate的优先级是1000。该属性默认值为0。

terminal(最后一组)- 如果设置为”true”,则表示当前的priority将会成为最后一组执行的directive。任何directive与当前的优先级相同的话,他们依然会执行,但顺序是不确定的(虽然顺序不确定,但基本上与priority的顺序一致。当前优先级执行完毕后,更低优先级的将不会再执行)。

scope - 如果设置为:
true - 将为这个directive创建一个新的scope作用域,而不是继承父作用域。

false - 默认值,使用现有的scope作用域。

{/属性名和绑定风格/} - 独立的scope。

独立scope与一般的scope的区别在于它不是通过原型继承于父scope的。这对于创建可复用的组件是很有帮助的,可以有效防止读取或者修改父级scope的数据。

绑定策略

@或@attr - 建立一个local scope property到DOM属性的绑定。因为属性值总是String类型,所以这个值总是返回一个字符串。如果没有通过@attr指定属性名称,那么本地名称将与DOM属性的名称一致。例如<widget my-attr=”hello {{name}}”>,widget的scope定义为:{localName:’@myAttr’}。那么,widget scope property的localName会映射出”hello {{name}}”转换后的真实值。name属性值改变后,widget scope的localName属性也会相应地改变(仅仅单向,与下面的”=”不同)。name属性是在父scope读取的。

=或=expression(绑定当前属性,它带来一个来自指令父scope的属性) - 在本地scope属性与parent scope属性之间设置双向的绑定。如果没有指定attr名称,那么本地名称将与属性名称一致。例如,widget定义的scope为:{localModel:’=myAttr’},那么widget scope property “localName”将会映射父scope的“parentModel”。如果parentModel发生任何改变,localModel也会发生改变,反之亦然。(双向绑定)

&或&attr - 传递一个来自父scope的函数,稍后调用。

controller - controller 构造函数。controller会在pre-linking步骤之前进行初始化,并允许其他directive通过指定名称的require进行共享(看下面的require属性)。这将允许directive之间相互沟通,增强相互之间的行为。

controller默认注入了以下本地对象:
$scope - 与当前元素结合的scope
$element - 当前的元素
$attrs - 当前元素的属性对象
$transclude - (A transclude linking function pre-bound to the correct transclusion scope)

require - 请求另外的controller,传入当前directive的linking function中。require需要传入一个directive controller的名称。如果找不到这个名称对应的controller,那么将会抛出一个error。名称可以加入以下前缀:
? - 不要抛出异常。这使这个依赖变为一个可选项。
^ - 允许查找父元素的controller

restrict - EACM的子集的字符串,它限制directive为指定的声明方式。如果省略的话,directive将仅仅允许通过属性声明:
E - 元素名称: <my-directive></my-directive>
A - 属性名: <div my-directive=”exp”></div>
C - class名: <div class=”my-directive:exp;”></div>
M - 注释 : <!-- directive: my-directive exp -->

template - 如果replace 为true,则将模版内容替换当前的HTML元素,并将原来元素的属性、class一并迁移;如果为false,则将模版元素当作当前元素的子元素处理。

templateUrl - 与template基本一致,但模版通过指定的url进行加载。因为模版加载是异步的,所以compilation、linking都会暂停,等待加载完毕后再执行。

replace - 如果设置为true,那么模版将会替换当前元素,而不是作为子元素添加到当前元素中。(注:为true时,模版必须有一个根节点)

transclude - 编译元素的内容,使它能够被directive所用。(如果当前元素,希望其他directive调用,就将其设为true,并在元素的节点上,增加<div ng-transclude></div> 就好,更高级的用法,目前我还在学习中)
true - 转换这个directive的内容。(这个感觉上,是直接将内容编译后搬入指定地方)
element - 转换整个元素,包括其他优先级较低的directive。(像将整体内容编译后,当作一个整体(外面再包裹p),插入到指定地方)

compile - 编译函数,整个运行周期中只执行一遍。(一般情况下,用compile即可。)

link - 链接函数,可以多次执行。具体用法参照上文代码

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值