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){...}
            };
        }
    };
});

重点在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‘
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;
                    };
                }
            };
        })
        ;

结果是在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‘
            }];
        }]);

再看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供别人使用。

时间: 2024-08-25 22:10:59

AngularJs(Part 11)--自定义Directive的相关文章

AngularJs中,如何在父元素中调用子元素为自定义Directive中定义的函数?

最近一段时间准备使用AngularJs中的自定义Directive重构一下代码. 在这里说明一下,把自定义控件封装成Directive并不一定是要复用,而是要让代码结构更加清晰.就好像你将一个长方法拆分成多个独立的小方法,也未必要复用它们一样.职责独立等一票好处,会让后期维护更加轻松. 在重构的过程中,我遇到了这样一个问题,先上图: 图一: 这就是我要重构的界面,由于之前时间紧,将这三个Filter和两个button都写在了一个页面中.当时我已经预感到,如果将这里面的状态都写到一个scope上,

AngularJS自定义Directive中link和controller的区别

在AngularJS中,自定义Directive过程中,有时用link和controller都能实现相同的功能.那么,两者有什么区别呢? 使用link函数的Directive 页面大致是: <button id="addItem">Add Item</button><without-Controller datasource="customers" add="addCustomer"></without-

AngularJS自定义Directive

什么时候需要自定义Directive? 1. 使你的Html更具语义化,不需要深入研究代码和逻辑即可知道页面的大致逻辑. 2. 抽象一个自定义组件,在其他地方进行重用. 看一下如下2个代码片段: 示例1: 1 <body> 2 <div> 3 <p>This is your class name.</p> 4 <div> 5 <p>Your teacher:</p> 6 <p>Mr. Wang</p>

AngularJS自定义Directive初体验

通常我们这样定义个module并随之定义一个controller. var app = angular.module('myApp', []); app.controller('CustomersController', ['$scope', function($scope){ var counter = 0; $scope.customer = { name:'', street:'' }; $scope.customers = [ { name:'', street:'' }, ... ];

angularjs取Sevice和directive的引用

取Sevice和directive的引用 3: Grab any Services We can grab a reference to any service using the injector function of element where ngApp was defined (or grab the $rootElement manually if using angular's bootstrap method): > angular.element('html').injecto

[AngularJS] &#39;require&#39; prop in Directive or Component

When use 'require', recommend to add some error check, for example: class ChildCtrl { constructor(){ // Get prop from parent ctrl if(this.parentCtrl){ this.childProp = this.parentCtrl.prop; } } } app.directive('someDirective', () => { return { requir

关于angular 自定义directive

关于angular 自定义directive的小结 首先我们创建一个名为"expander"的自定义directive指令: angular.module("myApp",[]).directive("expander",function(){ return{ //directive的一些属性(键值对形式)如下: /* restrict:'EA', replace:true, transclude:true, scope:{...}, templ

AngularJS自定义Directive与controller的交互

有时候,自定义的Directive中需要调用controller中的方法,即Directive与controller有一定的耦合度. 比如有如下的一个controller: app.controller('MyCtrl',function($scope){ $scope.load = function(){ console.log('loading more...') } }); 现在自定义一个Direcitve,需要调用MyCtrl这个controller中的load方法. app.direc

详解angularJs中自定义directive的数据交互

就我对directive的粗浅理解,它一般用于独立Dom元素的封装,应用场合为控件重用和逻辑模块分离.后者我暂时没接触,但数据交互部分却是一样的.所以举几个前者的例子,以备以后忘记. directive本身的作用域$scope可以选择是否封闭,不封闭则和其controller共用一个作用域$scope.例子如下: <body ng-app="myApp" ng-controller="myCtrl"> <test-directive><