angular之directive浅谈

angular之directive浅谈

directive就是angular提供的一种方法,他注重对DOM的操作,简化controller里面的操作,她可以根据需求对DOM变形以及行为操作,ng-controller,ng-model等就是angular内置的directive。这里说的directive是我们自己根据需求自定义的。

命名

directive的命名规则是多样的,并不局限与于种,如my:directive,my-directive,my_directive等等,但是推荐使用的是第二种my-directive;在js里对应的就是myDirective,就和普通的js样式写法一样,去掉-然后-后面的字母大写。

声明形式(restrict)

directive声明形式一共有四种:E,A,C,M。
E:<my-directive></my-directive>,通俗理解就是可以把directive名作为HTML标签名;
A:<div my-directive></div>,这个就是说directive名作为属性名;
C:<div class="my-directive sjf">,这个就是说directive名作为class名;
M:(//这个可以忽略)
directive默认的声明形式是A,就是说默认当做属性名

HTML模板指定

template和templateUrl,template就是直接把你想要的HTML模板写在template里面,templateUrl就是你把想要的HTML内容写在一个模板里面了,然后引入这个模板。
replace参数有俩个值,一个true,一个false,默认是false,true就是会把<div my-directive></div>替换成你的模板里面的内容,false就是把模板的内容插入进去。

directive的编译三阶段

1.将HTML转换成DOM,所以自定义HTML标签必须符合HTML格式

2.搜索匹配directive,执行directive上的compile方法

3.执行directive上的link方法以及进行scope和事件绑定

compile是在DOM渲染之前执行的就是把模板HTML渲染成想要的HTML的过程,compile方法的参数的element和attr是tElement和tAttr,就是说还是处于模板阶段,然后compile方法还可以返回一个函数,这个函数就是link要执行的函数,因为在一个directive里面,compile属性被设置后,link属性的方法就不会在被执行。所以这时就只有通过compile的返回函数来代替link方法要干的活了。

app.directive('sideBar',function(){
    return {
        link:function(){
            console.log('link');
        }, 
        compile:function(){
            console.log('compile');
            //return function(){
               // console.log('link');
            //};
        }
    }
})          -->结果只输出了compile,如果去掉注释就会输出link

然后这个compile方法返回的函数其实可以分为pre-link和post-link方法

app.directive('sideBar',function(){
    return {
        compile:function(){
            console.log('213');  //第一执行
            return {
                post:function(){
                    console.log('post');  //最后执行
                },
                pre:function(){
                    console.log('pre');  //第二执行
                }
            }
        }
    }
})
compile阶段结束之后,pre()的参数里面的element是模板编译之后的element,
<!-- HTML部分 --> 
<my-directive>
    <lever>{{name}}</lever>
</my-directive>   
<!-- js部分 -->
app.directive('myDirective',function(){
    return {
        restrict:'E',
        compile:function(tEle,tAttr){
            console.log(name+':compile =>' +tEle.html());
            return {
                pre:function(scope,ele,attrs){
                    console.log(name+':pre =>'+ele.html());
                },
                post:function(scope,ele){
                    console.log(name+':post =>'+ele.html());
                }
            }
        }
    }
});
结果是这样的

compile方法执行后的结果;
可以看到compile执行之前和之后的HTML是不一样的。

compile阶段发生的事情

在angular中compile用来改变DOM,首先在不执行js的时候,浏览器创建的element就是;当执行js之后,ng会遍历DOM,这时会发现my-directive,就会去执行一些函数,compile函数定义在这个指令对象里面,所以这时会被调用执行,并传递一个element对象做参数。并且会递归深度遍历DOM节点重复上述操作。
pre-link方法执行的时候是从最外层指令的依次往里执行,这样就会在所有的子指令pre-link之前执行,也就能够保证运行在他所有子指令以及自身的post-link和pre-link之前。
post-link方法是从最里层依次向外执行的,也就是说这个指令的post-link函数是最后才执行的,这样才能确保所有的子模板都渲染完成,这样自身的渲染才能真正的完成,post-link有人说就是相当于link方法。
示例如下:
<!-- html部分 -->
<my-directive-one>
     <my-directive-two>
         <my-directive-three>
            {{name}}
         </my-directive-three>
    </my-directive-two>
</my-directive-one> 
<!-- js部分 -->
function directiveFunction(name){
    return function(){
        return {
            restrict:'E',
            compile:function(tEle,tAttr){
                console.log(name+':compile =>' +tEle.html());
                return {
                    pre:function(scope,ele,attrs){
                        console.log(name+':pre =>'+ele.html());
                    },
                    post:function(scope,ele){
                        console.log(name+':post =>'+ele.html());
                    }
                }
            }
        }
    }
}
app.directive('myDirectiveOne',directiveFunction('myDirecitve1'));
app.directive('myDirectiveTwo',directiveFunction('myDirecitve2'));
app.directive('myDirectiveThree',directiveFunction('myDirecitve3'));

结果如图:pre和compile和post的节点层次执行顺序

最后各个方法使用的环境

compile适合于只有一个模板,然而要重复使用这个模板去修改DOM的环境,ng-repeat使用的就是这个思想,这样大大提高了性能
pre-link函数可以运行一些业务代码在compile函数执行完之后,在所有的子指令post-link函数执行之前。
post-link函数用来执行业务逻辑,因为这时本身的DOM以及深成子指令的DOM也已经渲染完成。