如何理解angular自定义指令directive的compile、link属性?

1、背景介绍

Directive(指令)是AngularJ非常强大而有有用的功能之一。它就相当于为我们写了公共的自定义DOM元素或CLASS属性或ATTR属性,并且它不只是单单如此,你还可以在它的基础上来操作scope、绑定事件、更改样式等。通过这个Directive,我们可以封装很多公共指令,比如分页指令、自动补全指令等等。然后在HTML页面里只需要简单的写一行代码就可以实现很多强大的功能。一般情况下,需要用Directive有下面的情景:
(1). 使你的Html更具语义化,不需要深入研究代码和逻辑即可知道页面的大致逻辑。
(2). 抽象一个自定义组件,在其他地方进行重用。

2.知识剖析

      directive的执行原理:
      在AngularJS应用启动前,指令都以html文本的形式保存在文本编辑器中。当该应用启动后,会经过两个阶段,即编译阶段和链接阶段。之后,作用域(scope)会同html进行绑定,应用会对html中dom的操作进行实时响应。第一阶段是compile,第二阶段是link。
      编译阶段: AngularJS会遍历整个html文档并根据JS中的指令定义来处理页面上声明的指令。换句话说, 在遍历dom时,所有的指令将被收集,但对dom树还没有进行数据绑定,此时对dom操作对性能影响很小。在编译阶段,同种 directive 在不同的 dom 节点出现一次,编译也会随之执行一次。然而,在这个阶段 scope 是无法访问到的。一个指令一旦编译完成,马上就可以通过编译函数对其进行访问。这个编译函数会返回一个模板函数,包含有完整的解析树。最后,模板函数被传递给编译后的dom树中每个指令定义的链接函数(link)。
      链接阶段: Angular 会把所有 directive 的事件监听器注册到dom中并建立对 scope(作用域)的监听,并且把一个 scope 加到 directive 中。由于链接阶段是在编译阶段之后进行的,所以这时的scope是可以访问的。

3.常见问题  

    compile 和 link 的用法及区别

4.解决方案

    compile用法:
compile函数负责对模板dom进行转换,它返回一个对象或者函数。compile本身相较于link函数不会那么频繁地使用。通常情况下,如果设置了compile函数,那就意味着可以在指令和实时数据被放到dom中之前对dom进行操作,在这个函数中进行例如添加或删除节点等dom操作都是安全的。

app.directive('myDirective', function() {
	     return {
			compile: function(element, attrs, transclude){
	            var curEle = angular.element('id');
	            return function(scope, element, attrs) {
	                 //链接函数
	            };
	        }
	     }
	});

    link函数用法:
ink函数负责将作用域和dom进行链接,并对元素的注册事件进行监听。而在这个操作执行之前,可以手动操作dom。如果有了编译函数,它会返回一个链接函数,不需要另外定义。一般来说,都可按照以下代码来定义link函数(该函数的参数列表是固定的)。

app.directive('myDirective', function() {
	     return {
	        link: function(scope, element, attrs, controller) {
	         //controller是require中指定的控制器,名字不能写错,不然对应不起来...
	        }
	     }
	});

    controller用法:
controller这里的属性值可以是一个字符串(控制器名称)或者函数(控制器内容)。如果属性值为字符串时,会以字符串为控制器的名字,查找在应用中已经注册过的控制器的构造函数。

app.directive('myDirective', function() {
	     return {
	        controller: function($scope, $element, $attrs, $transclude) {
	             //controller逻辑内容
	        }
	        or
	        controller: 'MyController'
	     }
	});

一般在控制器内部操作dom与AngularJS的风格不符,所以需要通过链接函数来实现这个功能。
自定义指令的控制器和link函数是可以进行互换的。控制器主要用来提供可在指令间复用的行为,但是链接函数只能在当前内部指令中定义行为,且无法在指令间复用。

    作用:
compile:负责对模板dom进行转换;
link: 负责将作用域和dom进行链接,并对元素的注册事件进行监听,只能在当前内部指令中定义行为,且无法在指令间复用;
controller:用来提供可在指令间复用的行为。

compile与link区别在于它们要做的事情不同,而link与controller在于这两个函数上的定位。

    compile和link的区别:
◆ compile函数的作用是对指令的模板进行转换;
◆ link的作用是在模板和视图之间建立关联,包括在元素上注册监听;
◆ scope在链接阶段才会被绑定到元素上,因此compile阶段操作scope会报错;
◆ 对于同一个指令的多个实例,compile只执行一次;而link对于每个实例都会执行一次;
◆ 一般情况下我们只要编写link函数就够了;
◆ 如果编写的自定义compile函数,自定义的link函数无效,因为compile函数应该返回一个link函数供后续处理;

5.代码实战

6.拓展思考

compile 和 link的执行顺序是怎样的?

:所有的指令都是先compile,然后preLink,然后postLink;
节点指令的preLink是在所有子节点指令preLink,postLink之前,所以一般这里可以通过scope给子节点传递一定的信息;
节点指令的postLink是在所有子节点指令preLink,postLink完毕之后,也就意味着,当父节点指令执行postLink时,子节点postLink已经都完成了,此时子dom树已经稳定,所以我们大部分dom操作,访问子节点都在这个阶段;
指令在link的过程,其实是一个深度优先遍历的过程,postLink的执行其实是一个回溯的过程;
节点上的可能有若干指令,在搜集的时候就会按一定顺序排列(通过byPriority排序),执行的时候,preLinks是正序执行,而postLinks则是倒序执行。

7.参考文献

参考一Angular自定义指令之compile, link, controller属性详解及实例演示
参考二angular.js指令中的controller,compile,link函数有什么不同?
参考三angular 指令详解(一)compile与link
参考四::angular指令中的preLink函数和postLink函数

8.更多讨论

1、问:指令有什么用
    可以通过指令来操作scope、绑定事件、更改样式。通过这个Directive,我们可以封装很多公共指令,比如分页指令、自动补全指令等等。然后在项目中可以进行复用,提高写代码效率。

2、问:什么时候要用指令
   答:
   1. 想要使Html更具语义化,不需要深入研究代码和逻辑即可知道页面的大致逻辑。
   2. 想要抽象一个自定义组件,在其他地方进行重用。

3、问:restric怎么用?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值