这里是修真院前端小课堂,每篇分享文从
八个方面深度解析前端知识/技能,本篇分享的是:
【angular js自定义指令 directive 如何使用?为什么要使用封装的自定义指令? 】
1.背景介绍
1.1什么是指令
AngularJS与jQuery最大的区别在哪里?我认为,表现在数据双向绑定,实质就是DOM的操作形式不一样。
JQuery通过选择器找到DOM元素,再赋予元素的行为;
而AngularJS则是,将指令与DOM绑定在一起,再扩展指令的行为。
所以AngularJS开发最理想的结果就是,在页面HTML与CSS的设计时,设计工程师只需要关注指令的使用;
而在背后的逻辑开发上,架构工程师则是不需要知道如何操作DOM,只需要关注指令背后的行为要如何实现就行;
测试工程师也可以开发针对指令的单元测试。
指令就是DOM与逻辑行为的媒介,本质就是DOM绑定的独立逻辑行为函数。
AngularJS 通过被称为 指令 的新属性来扩展 HTML。 AngularJS 通过内置的指令来为应用添加功能。 AngularJS 允许你自定义指令。
如一些内置指令:ng-repeat 指令会重复一个 HTML 元素
ng-app 指令定义了 AngularJS 应用程序的 根元素
ng-model 指令 绑定 HTML 元素 到应用程序数据。
除了 AngularJS 内置的指令外,我们还可以创建自定义指令。
你可以使用 .directive 函数来添加自定义的指令。
2.知识剖析
directive( )模块解析
directive( )方法可以接受两个参数:
- name (字符串)
指令的名字,用来在视图中引用特定的指令。
- factory_function (函数)
这个函数返回一个对象,其中定义了指令的全部行为。 $compile 服务利用这个方法返回的对
象,在DOM调用指令时来构造指令的行为。当AngularJS启动应用时,它会把第一个参数当作一个字符串,并以此字符串为名来注册第
二个参数返回的对象。AngularJS编译器会解析主HTML的DOM中的元素、属性、注释和CSS类名
中使用了这个名字的地方,并在这些地方引用对应的指令。当它找到某个已知的指令时,就会在
页面中插入指令所对应的DOM元素。
restrict(字符串)
restrict 是一个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明。默
认AngularJS认为 restrict 的值是 A ,即以属性的形式来进行声明。
可选值如下:
当模板在上面代码中返回时,你可以把以下的属性列表应用于指令定义返回的对象
restrict(字符串)
restrict 是一个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明。默
认AngularJS认为 restrict 的值是 A ,即以属性的形式来进行声明。
template (字符串或函数)
template 参数是可选的,必须被设置为以下两种形式之一:
一段HTML文本;
一个可以接受两个参数的函数,参数为 tElement 和 tAttrs ,并返回一个代表模板的字符
串。 tElement 和 tAttrs 中的 t 代表 template ,是相对于 instance 的。在讨论链接和编译
设置时会详细介绍,模板元素或属性与实例元素或属性之间的区别。
AngularJS会同处理HTML一样处理模板字符串。模板中可以通过大括号标记来访问作用域,
例如 {{ expression }} 。
templateUrl (字符串或函数)
templateUrl 是可选的参数,可以是以下类型:
一个代表外部HTML文件路径的字符串;
一个可以接受两个参数的函数,参数为 tElement 和 tAttrs ,并返回一个外部HTML文件
路径的字符串。
无论哪种方式,模板的URL都将通过AngularJS内置的安全层,特别是 $getTrusted
ResourceUrl ,这样可以保护模板不会被不信任的源加载。
transclude
transclude 是一个可选的参数。如果设置了,其值必须为 true ,它的默认值是 false 。
嵌入有时被认为是一个高级主题,但某些情况下它与我们刚刚学习过的作用域之间会有非常
好的配合。使用嵌入也会很好地扩充我们的工具集,特别是在创建可以在团队、项目、AngularJS
社区之间共享的HTML代码片段时。
嵌入通常用来创建可复用的组件,典型的例子是模态对话框或导航栏。
我们可以将整个模板,包括其中的指令通过嵌入全部传入一个指令中。这样做可以将任意内
容和作用域传递给指令。
transclude 参数就是用来实现这个目的的,指令的内部可以访问外部
指令的作用域,并且模板也可以访问外部的作用域对象。
为了将作用域传递进去, scope 参数的值必须通过 {} 或 true 设置成隔离作用域。如果没有设
置 scope 参数,那么指令内部的作用域将被设置为传入模板的作用域。
只有当你希望创建一个可以包含任意内容的指令时,才使用 transclude: true 。
3.常见问题
如何创建操作DOM的指令?
4.解决方案
要修改DOM的指令通常使用链接选项来注册DOM侦听器以及更新DOM。它是在模板被克隆后执行的,是指令逻辑将被执行的地方。
链接的功能与下面的签名,功能链接(scope,element,attrs,controller,transcludeFn){…},:
scope是一个Angular scope 对象。
element是这个指令匹配的jqlite包装元素。
attrs是一个哈希对象,其具有键值对标准化属性名及其相应的属性值。
controller是指令的必需控制器实例(s)或它自己的控制器(如果有的话)。确切的值取决于指令的要求属性。
transcludeFn是一个连接函数预绑定到正确的连接函数。
在我们的link函数中,我们希望每秒更新显示的时间,或者每当用户更改指令绑定到的时间格式字符串时。
我们将使用$ interval服务定期调用处理程序。这比使用$timeout更容易,但也可以更好地使用端到端测试,
我们希望确保在完成测试之前完成所有$ timeouts。如果指令被删除,我们还希望删除$ interval,这样我们就不会引入内存泄漏。
5.编码实战
6.扩展思考
指令作用
它就相当于为我们写了公共的自定义DOM元素或CLASS属性或ATTR属性,并且它不只是单单如此,你还可以在它的基础上来操作scope、绑定事件、更改样式等。
通过这个Directive,我们可以封装很多公共指令,比如分页指令、自动补全指令等等。
然后在HTML页面里只需要简单的写一行代码就可以实现很多强大的功能。
7.参考文献
参考一: 学习AngularJs:Directive指令用法
参考二: angularJS自定义指令
8.更多讨论
1.为什么不推荐Angular和JQuery混合使用?
Angular在DOM操作上面不如jQuery方便,而jQuery在页面的数据构造方面不如Angular方便
那么Angular的jqlite怎么样呢,确实这个东西能够提供最基础的DOM操作,可以保证你够用,但是在你能够自己写出各种动效插件之前,其实你还是需要使用到其他人写到的插件的。
2.什么是内存泄漏?
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
3.scope里的@&=是什么意思?
directive 在使用隔离 scope 的时候,提供了三种方法同隔离之外的地方交互。这三种分别是:
@ 绑定一个局部 scope 属性到当前 dom 节点的属性值。结果总是一个字符串,因为 dom 属性是字符串。
& 提供一种方式执行一个表达式在父 scope 的上下文中。如果没有指定 attr 名称,则属性名称为相同的本地名称。
= 通过 directive 的 attr 属性的值在局部 scope 的属性和父 scope 属性名之间建立双向绑定。