AngularJS教程(自定义指令的神秘化)

本文概述

  • AngularJS指令生命周期的四个功能
  • 相对于其他指令的AngularJS指令函数执行
  • AngularJS指令功能说明:深入研究
  • 指令功能表
  • 摘要
随着JavaScript作为全栈语言的迅速发展, 越来越多的应用程序正在利用使Web浏览器能够处理更多UI处理的框架, 例如数据绑定, 管理数据视图, 转换数据和许多其他服务。 AngularJS是最强大, 可扩展和最受欢迎的框架之一, AngularJS框架最有用的组件之一就是指令。 AngularJS提供了许多有用的指令, 更重要的是, 它提供了丰富的框架来创建自定义指令。
什么是指令?简而言之, 指令是JavaScript函数, 用于操纵HTML DOM元素并向其添加行为。指令可能非常简单, 也可能非常复杂。因此, 牢牢掌握操纵它们的许多选项和功能至关重要。
在本教程中, 将探索作为指令执行的四个函数, 并将其应用于DOM, 并提供示例。这篇文章假定你对AngularJS和自定义指令有所了解。如果你是Angular的新手, 可能会喜欢有关构建第一个AngularJS应用程序的教程。
AngularJS指令生命周期的四个功能 有许多选项可以配置, 这些选项如何相互关联很重要。当AngularJS编译并链接DOM时, 每个指令都会经历类似于生命周期的过程。在呈现页面之前, 指令生命周期在AngularJS引导过程中开始和结束。在指令的生命周期中, 定义了四个可以执行的功能。通过每种方法, 开发人员都可以在生命周期的不同点控制和自定义指令。
这四个功能是:编译, 控制器, 预链接和后链接。
编译功能允许指令在DOM进行编译和链接之前对其进行操作, 从而允许它添加/删除/更改指令, 以及添加/删除/更改其他DOM元素。
控制器功能有助于指令通信。兄弟姐妹和子代指令可以请求其兄弟姐妹的控制者和父母进行信息交流。
预链接功能允许在后链接过程开始之前对$ scope进行私有操作。
链接后方法是该指令的主要工作方式。
在该指令中, 发生编译后DOM操作, 配置了事件处理程序, 并且监视和其他内容也进行了配置。在指令的声明中, 四个函数的定义如下。
.directive("directiveName", function () {return { controller: function() { // controller code here... }, compile: {// compile code here...return {pre: function() { // pre-link code here... }, post: function() { // post-link code here... } }; } } })

通常, 并非所有功能都需要。在大多数情况下, 开发人员只需按照以下模式创建一个控制器和后链接功能。
.directive("directiveName", function () {return {controller: function() { // controller code here... }, link: function() { // post-link code here... } } })

【AngularJS教程(自定义指令的神秘化)】在此配置中, 链接是指链接后功能。
无论定义了全部还是部分功能, 它们的执行顺序都很重要, 尤其是相对于AngularJS应用程序的其余部分而言。
相对于其他指令的AngularJS指令函数执行 考虑以下HTML片段, 其中将指令parentDir, childDir和grandChildDir应用于HTML片段。
< div parentDir> < div childDir> < div grandChildDir> < /div> < /div> < /div>

指令内以及相对于其他指令的功能的执行顺序如下:
  • 编译阶段
    • 编译函数:parentDir
    • 编译函数:childDir
    • 编译函数:grandChildDir
  • 控制器和预链接阶段
    • 控制器功能:parentDir
    • 链接前功能:parentDir
    • 控制器功能:childDir
    • 链接前功能:childDir
    • 控制器功能:grandChildDir
    • 链接前功能:grandChildDir
  • 链接后阶段
    • 链接后功能:grandChildDir
    • 链接后功能:childDir
    • 链接后功能:parentDir
AngularJS教程(自定义指令的神秘化)

文章图片
AngularJS指令功能说明:深入研究 编译阶段首先发生。本质上, 编译阶段将事件侦听器附加到DOM元素。例如, 如果特定的DOM元素绑定到$ scope属性, 则将允许使用$ scope属性值更新的事件侦听器应用于DOM元素。编译过程从启动AngularJS应用程序的根DOM元素开始, 并使用深度优先遍历遍历DOM的分支, 先编译父级, 然后编译其子级一直到叶节点。
编译完成后, 就不能再从DOM中添加或删除指令了(尽管可以通过直接使用编译服务来解决此问题。下一阶段是为所有指令调用控制器和预链接函数。当控制器调用后, $ scope可用并且可以使用。注入控制器的$ e元素包含已编译的模板, 但不包括已包含子内容的内容(包含内容是该指令所在的开始和结束HTML标记之间的内容根据定义, MVC模式中的控制器只是将模型传递给视图并定义用于处理事件的函数, 因此, 指令的控制器不应出于以下两个原因而修改指令的DOM:控制器, 并且子元素的内容没有添加到DOM中, 那么除了修改$ scope之外, 控制器还有什么作用? h父指令。控制器功能本身应被视为控制器对象, 如果子指令要求, 则该控制器对象将传递到子指令的后链接函数中。因此, 控制器通常用于通过创建具有可用于其兄弟和子指令的属性和方法的对象来促进指令通信。父指令无法确定子指令是否可以要求其控制器, 因此最好将此方法中的代码限制为子指令可以安全使用的函数和属性。
控制器功能后, 将执行预链接功能。预链接功能对很多人来说都是神秘的。如果你在Internet和书籍中阅读了大量文档, 则人们会说此功能仅在极少数情况下使用, 并且人们几乎永远不需要它。然后, 这些相同的解释无法给出可以使用它的情况的示例。
预链接功能实际上一点也不复杂。首先, 如果你查看AngularJS源代码, 你将找到一个很好的预链接功能示例:指令ng-init使用它。为什么?这是执行涉及$ scope的私人代码的好方法;兄弟指令和子指令无法调用的代码。与控制器功能不同, 预链接功能不会传递到指令中。因此, 它可用于执行修改其指令的$ scope的代码。指令ng-init正是这样做的。当ng-init的预链接函数执行时, 它只是针对指令的$ scope执行传递到指令中的JavaScript。执行结果可通过$ scope的原型继承在其控制器, 预链接和后链接函数执行期间对子指令的继承而获得, 但无法访问这些子指令以重新执行父级的预链接函数中的代码。同样, 该指令可能需要执行与希望使其私有的$ scope无关的其他代码。
一些经验丰富的AngularJS开发人员会说, 此私有代码仍可以放在控制器中, 然后不由child指令调用。如果该指令仅由编写该指令的原始开发人员使用, 则该参数将成立, 但是如果该指令将由其他开发人员分发和重用, 则将私有代码封装在预链接功能中可能会非常有益。由于开发人员永远不知道自己的指令将如何在一段时间内重新使用, 因此保护私有代码免于子指令的执行是一种封装指令代码的好方法。我认为将指令通信公共代码放置在控制器功能中, 并将私有代码放置在预链接功能中是一种好习惯。像控制器一样, 由于子指令的内容尚未链接, 因此预链接永远不应执行DOM操作或执行跨接函数。
对于每个指令, 其控制器和预链接功能在其子指令的控制器和预链接功能之前执行。一旦所有指令的控制器和链接前阶段完成, AngularJS就开始链接阶段, 并为每个指令执行链接后函数。链接阶段从叶DOM节点开始, 一直到根DOM节点, 与编译, 控制器和预链接执行流程相反。链接后DOM遍历遵循一个深度优先的路径。当链接每个子指令时, 将执行其后链接功能。
后链接功能是在自定义AngularJS指令中最常实现的功能。在此功能中, 几乎所有合理的事情都可以完成。可以操作DOM(仅适用于自身和子元素), $ scope可用, 可以使用父指令的控制器对象, 可以运行transclude函数, 等等。但是, 存在一些限制。无法将新指令添加到DOM, 因为它们不会被编译。此外, 所有DOM操作都必须使用DOM函数来完成。只需在DOM元素上调用html函数并传入新的HTML, 即可删除在编译过程中添加的所有事件处理程序。例如, 这些将无法正常工作:
element.html(element.html());

or
element.html(element.html() + "< div> new content< /div> ");

该代码不会导致HTML发生更改, 但是重新分配DOM元素的字符串版本将删除在编译过程中创建的所有事件处理程序。通常, 后链接功能用于连接事件处理程序, $ watches和$ observes。
一旦所有的链接后函数都执行完毕, $ scope将被应用到已编译和链接的DOM结构中, 并且AngularJS页面将变为活动状态。
指令功能表 下面的图表列出了每个功能的用途, 执行时可以使用的功能以及如何正确使用每个功能的最佳做法。
执行命令 指令功能 判决 包含 $范围 可被儿童致电
1 编译 尚未编译DOM, 但已将模板加载到DOM元素内容区域。指令可以添加和删除。可以使用DOM函数和HTML字符串替换来操作DOM。 Transclude函数可用, 但已弃用, 不应调用。 无法使用。 子元素不能调用函数。
2 控制者 已编译的DOM元素可用, 但不应修改。排除的子内容尚未添加到DOM元素。不应发生DOM更改, 因为这是一个控制器并且被链接的子内容尚未链接到其中。 Transclude函数可用, 但不应调用。 $ scope可用并且可以使用。函数参数是使用$ injector服务注入的。 函数被传递到子指令链接函数中, 并且可以被它们调用。
3 预链接 已编译的DOM元素可用, 但由于尚未链接子指令DOM元素, 因此不应进行修改。 Transclude函数可用, 但不应调用。 $ scope可用并且可以修改。 子指令不能调用该函数。但是可以调用父指令的控制器。
4 链接后 可以使用已编译的DOM元素和子指令DOM元素。只能使用DOM函数修改DOM(不能替换HTML), 并且只能添加不需要编译的内容。不允许添加/删除指令。 Transclude函数可用并且可以被调用。 $ scope可用并且可以使用。 指令子级不能调用, 但是可以调用父指令的控制器。
摘要 在本教程中, 我们了解了AngularJS指令的用途, 执行顺序和整体功能, 以及四种指令功能(编译, 控制器, 前链接和后链接)中每个功能的用途。在这四个函数中, 控制器和后链接是最常用的, 但是对于需要对DOM进行更好控制或需要私有作用域执行环境的更复杂的指令, 可以使用编译和预链接功能。

    推荐阅读