zoukankan      html  css  js  c++  java
  • AngularJs(Part 11)--自定义Directive

    先对自定义Directive有一个大体的映像

    myModule.directive('myDirective',function(injectables){
        var directiveDefinitionObject={
            restrict:string,
            priority:number,
            template:string,
            templateUrl:string,
            replace:bool,
            transclude:bool,
            scope:bool or object,
            controller:function controllerConstructor($scope,$element,$attrs,$transclude){...},
            require:string,
            link:function postLink(scope,iElement,iAttrs){...},
            compile:function compile(tElement,tAttrs,transclude){
                ...
                return {
                    pre:functionLink(scope,iElement,iAttrs,controller){...},
                    post:functionLink(scope,iElement,iAttrs,controller){...}
                };
            }
        };
    });
    View Code

     重点在directiveDefinitionObject这个对象。这个对象当中有些属性是互相排斥的,即:有了A属性,就不需要B属性。但大部分是可选的

    以下是详细解释各个属性的作用
    1. restrict: 决定directive是做HTML tag,属性,类或者是注释,只能在 'E','A','C','M'或者这四个字母的任意组合中取值。参考下表
        值      例子
        E        <my-directive></my-directive>
        A        <div my-directive='abc'></div>
        C        <div class='my-directive:abc'></div>
        M        <!--this is abc my-directive:abc -->
        restrict默认是A,如果一个directive既想用在Tag中也想用在注释中,那么就用 'EM'。

       注意:Directive名字是myDirective,但是使用时,无论是在HTML tag,还是属性,还是类中都是 my-directive。 如果Directive名字是LoginInBar,那么使用时就用login-in-bar.(AngularJS会进行奇怪的名称转换
    2. priority 设置优先级,数字大的先运行。一个例子是ng-repeat ,必须要先跑ng-repeat,生产出重复的对象,再跑其他
    3. template和templateUrl 模板或者模板地址。有时我们把一大段HTML片段包装在一个AngularJS中,如我只想用一个<hello></hello>来表示<div>hello <span style='color:red;'>world</span></div>那么可以把template设置为这一段字符串,或者写道另一个文件中用templateUrl引用。当然,还可以通过其他方法加载模板,然后把它们存在$templateCache中,如下。
       module.run(function($templateCache){
            $templateCache.put("a.html","<div>hello <span style='color:red;'>world</span></div>");
       });
    4. transclude 有时我们想保留原始的内容,并把它们添加到模板中,如有<hello>,we have fun</hello>。 想实现的效果是<div>hello world, we have fun</div>。如果我们设置了template为

    <div>hello world</div>,那么"we have fun"这一段不见了,现在设置transclude为true,并把template设置为<div>hello world<span ng-transclude></span></div>,就可以达成需要的效果了。注意template中多了个ng-transclude
    5.compile和link
        AngularJS的directive要起作用必须经过两个阶段:
        1) compile阶段,在该阶段AngularJS搜寻template中的整个DOM树,找到所有注册的其他directive,把他们按照各自的templat、replace等设置转换为DOM,运行各自的compile的function
        2) link阶段,在该阶段主要负责保持model和view的一致性,就是各种加监听器。在这个阶段scope在被注入到link中,所有的directive才有用
        
        ...
        
    6.scope AngularJS提供了三种scope给directive
        1).就用DOM中已经存在的scope  (false)
        2).继承自从已经存在的scope,可以访问父级scope中的所有properties  (true)
        3).一个独立的scope。不可以访问父级scope的properties ,但他有一个$parent属性指向父级scope  (一个{/*properties*/}对象)
        对于前两种没什么好说的,对于第三种,看一个例子。
        现在想完成一个点击之后显示一些div的功能。HTML代码如下:
        <div ng-controller='MyController'>
            <expander expand-title='title' expand-text='text' expand-click='change()'></expander>
        </div>
        javascript代码如下:

    angular.module('test',[])
            .controller('MyController',['$scope',function($scope){
                    $scope.title='click me i am the title';
                    $scope.text='well ,i was hidden but now i am shown';
                    $scope.change=function(){
                        $scope.text='haha i change myself';
                    };                
                }])
            .directive('expander',function(){
                return {
                    restrict:'E',
                    replace:true,
                    transclude:true,
                    template:['<div>',
                                '<div id="d1" ng-click="toggle()">{{scopeTitle}}</div>',
                                '<div id="d2" ng-show="showMe" ng-transclude>{{scopeText}}</div>',
                                '<div id='d3' ng-click="scopeChange()">click me to change</div>',
                              '</div>'].join(''),
                    scope:{scopeTitle:'@expandTitle',
                            scopeText:'=expandText',
                            scopeChange:'&expandClick'},
                    link:function(scope,element,attributes){
                        scope.showMe=false;
                        scope.toggle=function(){
                            scope.showMe=!scope.showMe;
                        };
                    }
                };
            })
            ;
    View Code

        结果是在d1中显示的是title,因为scopeTitle取得是'@expandTitle',意思是把expand-title的属性值当作字符串传给scopeTitle;

        而d2中显示的是“well ,i was hidden but now i am shown”,因为scopeText取得是'=expandText',意思是把expand-text的值当作变量名,在父级scope中找到同名的变量,把这个变量的值传给           scopeText;
        再看d3中的ng-click,它的值是通过scopeChange:'&expandClick'传进来的,expand-click的值是父级scope中的scope方法。所以’&'可以用来传递方法。

    4.controller directives之间需要互相通信是,可以通过controller来进行
        controller: function($scope,$element,$attrs,$transclude){}
        其他的directive可以接受这个controller:通过require属性 require:"^?directiveName".
        directiveName:是驼峰表示法的directive的名字。需要哪个directive的controller就写哪个的名字;
        ^:默认的AngularJS是找同一个元素内的directive,如果加上了“^”,AngularJS沿着DOM树往上找,知道找到为止;
        ?:如果没找到controller,AngularJS会丢出一个错误,加上了"?"表示没找到也没关系;
        重写一个例子,要求出现三个tag,点击其中一个的话,自己展开,别的收缩  

    angular.module('test',[])
            .directive('accordion',function(){
                return {
                    restrict:"E",
                    replace:true,
                    transclude:true,
                    template:'<div ng-transclude></div>',
                    controller:function(){
                        var expanders=[];
                        this.getOpened=function(selected){
                            angular.forEach(expanders,function(expander){
                                if(selected!=expander){
                                    expander.showMe=false;
                                }
                            });
                        };
                        this.addExpander=function(expander){
                            expanders.push(expander);
                        };
                    }
                };
            })
            .directive('expander',function(){
                return {
                    restrict:'E',
                    replace:true,
                    transclude:true,
                    require:"^?accordion",
                    template:['<div>',
                                '<div ng-click="toggle()">{{scopeTitle}}</div>',
                                '<div ng-show="showMe" ng-transclude>{{scopeText}}</div>',
                              '</div>'].join(''),
                    scope:{scopeTitle:'=expandTitle',
                            scopeText:'=expandText',
                          },
                    link:function(scope,element,attrs,accordionController){
                        scope.showMe=false;
                        accordionController.addExpander(scope);
                        scope.toggle=function(){
                            scope.showMe=!scope.showMe;
                            accordionController.getOpened(scope);
                        };
                    }
                };
            })
            .controller('MyController',['$scope',function($scope){
                $scope.expanders=[{
                    title:'click1',
                    text:'text1'
                },{
                    title:'click2',
                    text:'text2'
                },{
                    title:'click3',
                    text:'text3'
                }];
            }]);
    View Code

        再看HTML:
        <div ng-controller='MyController'>
            <accordion>
                <expander ng-repeat='expander in expanders' expand-title='expander.title' expand-text='expander.text'></expander>
            <accordion>
        </div>
        可以想见,我要实现一个展开就其他收缩的功能,我得有一个地方存储所有expander的状态。尽管在expander的link中的scope可以访问到MyController的scope从而可以找到expanders,但是最好不要这样做,还是隔离的好。那么最好的地方就是在expander的父元素accordion中存储。accordion相当于一个仓库,他提供了API供别人使用。
       

  • 相关阅读:
    audio之点击图标切换音频播放状态以及替换当前图标
    js之ajax的封装
    JavaScript之ajax的作用、流程以及如何设置请求头
    BFC的理解
    2016年总结
    如何用shared_ptr减少锁的争用
    webrtc初识
    2015总结与2016展望
    记一次程序排错与std::getline
    spawn协程学习
  • 原文地址:https://www.cnblogs.com/formyjava/p/4172585.html
Copyright © 2011-2022 走看看