手机版

angularjs命令中编译和链接函数的详细说明

时间:2021-09-09 来源:互联网 编辑:宝哥软件园 浏览:

通常,当您使用ng中的指令时,您最常使用link属性。下面这篇文章将告诉你complie,pre-link和post-link的用法和区别。

angularjs中的指令令人惊叹,允许您创建高度语义化和可重用的组件,这可以理解为web组件的先驱。

网上有很多关于如何使用说明书的文章和相关书籍。相比之下,编译和链接几乎没有区别,更不用说前链接和后链接了。

大多数教程只是说编译将用于ng,建议您只使用link属性,这是大多数指令示例中的情况

这是非常不幸的,因为正确理解这些函数之间的差异将提高您对ng内部运行机制的理解,并帮助您开发更好的自定义指令。

所以跟着我一步一步看下面的内容,了解这些功能是什么,应该在什么时候使用

本文假设您对指令有一定的理解,如果没有,强烈建议您阅读本文《Angular JS开发人员指南》中关于指令的部分

你如何处理NG中的指令

在开始分析之前,让我们看一下指令是如何在ng中处理的。

当浏览器呈现一个页面时,它本质上读取html标签,然后构建dom节点,并在创建dom树时向我们广播一个事件。

当您使用脚本标记在页面上加载ng应用程序代码时,ng会监听上面的dom完成事件,并查找带有ng-app属性的元素。

当找到这样的元素时,ng从这个元素开始处理dom,所以如果ng-app被添加到html元素中,ng将从html元素中处理dom。

从这个起点开始,ng开始递归搜索符合应用程序中定义的指令规则的所有子元素。

事实上,ng如何处理指令取决于定义时的对象属性。您可以定义编译或链接函数,或者使用链接前和链接后函数来代替链接。

那么这些函数有什么区别呢?为什么要用?什么时候用?

带着这些问题,跟着我一步一步地回答这些谜团

一段代码

为了解释这些函数之间的区别,我将使用下面一个容易理解的例子

1.如果您有任何问题,请不要犹豫,在下面添加您的评论。

请看下面的html标签代码

复制代码如下: level-1 level-2 level-3 hello/level-3/level-2/level-1

然后是一段js代码

复制代码如下: varaapp=angular . module(' plunker ',[]);

function create directive(name){ return function(){ return { restrict : ' E ',compile: function(tElem,TatRS){ console . log(name ' : compile ');返回{ pre:函数(scope,iElem,iAttrs){ console . log(name ' : pre link ');},post:函数(scope,iElem,iAttrs){ console . log(name ' : post link ');} } } } } }

app.directive('levelOne ',create directive(' level one '));app.directive('levelTwo ',createDirective(' level two '));app.directive('levelThree ',create directive(' level three '));

结果很简单。让ng处理三个嵌套指令,每个指令都有自己的编译、预链接、后链接函数,每个函数都会在控制台打印一行来标识自己。

这个例子可以让我们简单理解ng在处理指令时的内部流程

代码输出

下面是控制台中输出结果的屏幕截图

如果你想自己尝试这个例子,请点击这个plnkr,然后在控制台查看结果。

分析代码

首先要注意的是,这些函数的调用顺序是:复制代码如下:调用://CompilePhase//level one :编译函数//LevelTwo :编译函数//LevelThree :编译函数

//PRE-LINK PHASE//level one : PRE-LINK函数被调用//level two : PRE-LINK函数被调用//level three : PRE-LINK函数被调用

//POST-LINK阶段(注意顺序相反)//调用levelThree: post link函数//调用levelTwo: post link函数//调用levelOne: post link函数

这个例子清楚地表明,ng在链接之前编译所有指令,然后将链接分为链接前和链接后阶段。

请注意,编译和前链接是按顺序执行的,但后链接正好相反。

因此,上面已经明确了不同的阶段,但是编译和预链接有什么区别呢?它们的执行顺序都是一样的,为什么要分成两个不同的功能呢?

数字正射影像图

为了更深入地挖掘,让我们简单地修改上面的代码,这也将打印每个函数中参数列表中的元素变量

复制代码如下: varaapp=angular . module(' plunker ',[]);

function create directive(name){ return function(){ return { restrict : ' E ',compile: function(tElem,TatRS){ console . log(name ' : compile=' tElem . html());返回{ pre:函数(scope,iElem,iAttrs){ console . log(name ' : pre link=' IElem . html());},post:函数(scope,iElem,iAttrs){ console . log(name ' : post link=' IElem . html());} } } } } }

app.directive('levelOne ',create directive(' level one '));app.directive('levelTwo ',createDirective(' level two '));app.directive('levelThree ',create directive(' level three '));

注意console.log中的输出,除了原来的html标签,基本没有变化。

这将加深我们对这些功能的理解。

再次运行代码以查看

输出

下面是控制台中输出结果的屏幕截图

如果你想自己运行看看效果,可以点击这个plnkr,然后在控制台查看输出。

观察

输出dom的结果可以暴露一些有趣的事情。dom的内容在编译和预链接功能上有所不同

发生了什么?

编制

我们已经知道,当ng发现dom被构建时,它就开始处理dom。

因此,当ng遍历dom时,他遇到了level-one元素,从它的定义中,他知道他必须执行一些必要的功能

因为编译函数是在一级指令的指令对象中定义的,所以它将被调用并传递一个元素对象作为它的参数

如果仔细观察,您会发现当浏览器创建这个元素对象时,它仍然是最原始的html标记

1.在ng中,通常使用原始dom来标识模板元素,所以我在定义compile函数的参数时使用了名称tElem,这个变量指向模板元素。

一旦levelone指令中的编译函数运行,ng将递归遍历其dom节点,然后在level-2和level-3上重复这些操作。

后链接

在进入链接前功能之前,我们先来看看链接后功能。

2.如果在定义指令时只使用链接函数,ng会把这个函数当作后链接,所以我们需要先讨论这个函数。在ng遍历所有dom并运行所有编译函数之后,它将反向调用关联的链接后函数。

Dom现在开始反转并执行链接后功能。所以这个反向调用之前看起来有点奇怪,但其实很有意义。

当包含子指令的指令后链接运行时,反向后链接规则可以保证其子指令的后链接已经运行。

因此,在运行一级指令的后链接功能时,我们可以保证二级和三级的后链接已经实际运行。

这就是为什么人们认为后链接是编写业务逻辑最安全或默认的地方。

但是为什么这里的元素不同于编译中的元素呢?

一旦ng调用了指令的编译函数,它将创建一个模板元素的元素实例对象,并为其提供一个作用域对象。这个作用域可能是一个新的实例,可能已经存在,可能是一个子作用域,也可能是一个独立的作用域,这取决于指令定义对象中的作用域属性值。

因此,当链接发生时,实例元素和作用域对象已经可用,并通过ng作为参数传递给链接后函数的参数列表。

1.就我个人而言,我总是使用iElem名称来定义链接函数的参数,它指向一个元素实例

因此,后链接(前链接)函数的元素参数对象是元素实例,而不是模板元素。

所以上面例子中的输出是不同的

预链接

当您编写一个后链接函数时,您可以保证它的所有子指令的后链接函数在执行后链接函数时已经被执行。

在大多数情况下,它可以做得更好,所以我们通常使用它来编写指令代码。

然而,ng为我们提供了一个额外的钩子机制,即预链接功能,它可以确保在执行所有子指令的后链接功能之前,运行一些其他代码。

这句话值得反复推敲

可以保证在元素实例上以及在其所有子指令的后链接操作之前执行前链接功能。

因此,反向链接后功能是有意义的,执行链接前功能是原来的顺序

这也意味着,预链接功能在其所有子指令的预链接功能之前运行,因此完整原因是:

可以保证元素的前链接功能在它的所有子指令的后链接和前链接之前执行。见下图:

回顾

如果我们回顾上面的原始输出,我们可以清楚地认识到发生了什么。复制代码如下://这里的元素还是原来的模板元素。

//COMPILE PHASE //levelOne:编译函数在原始DOM上调用//levelTwo:编译函数在原始DOM上调用//levelThree:编译函数在原始DOM上调用

//从这里开始,元素已经被实例化并且//被绑定到一个范围//(例如NG-REPEAT将有多个实例)

//PRE-LINK PHASE//level one : PRE-LINK函数在元素实例上调用//level two : PRE-LINK函数在元素实例上调用//level three : PRE-LINK函数在元素实例上调用

//POST-LINK PHASE(注意顺序相反)//level 3 : POST LINK函数在元素实例上调用//levelTwo: post link函数在元素实例上调用//levelOne: post link函数在元素实例上调用

概述

回顾以上分析,我们可以描述这些函数:的区别和用法

编译函数

在ng创建原始dom实例和范围实例之前,使用编译函数更改原始dom(模板元素)。

可以应用于需要生成多个元素实例时只有一个模板元素的情况。ng-repeat就是最好的例子。它在编译函数阶段改变原dom生成多个原dom节点,然后每个节点生成一个元素实例。因为编译只运行一次,所以当您需要生成多个元素实例时,它可以提高性能。

模板元素和相关属性作为参数传递给编译函数,但此时不能使用范围。

下面是函数外观:复制代码如下:/* * *编译函数* * @ param telem-template element * @ param tatattrs-template element的属性*/函数(telem,tatattrs){ 0

//.

};

预链接功能

使用前链接函数,您可以在ng执行编译函数之后,但在其所有子指令的后链接函数执行之前,运行一些业务代码。

范围对象和元素实例将作为参数传递给预链接函数:

以下是该函数的外观:复制代码如下:/* * *预链接函数* * @ param scope-与此历史相关联的作用域* @ param ielem-instance element * @ param iAttrs-实例元素的属性*/函数(scope,iElem,iAttrs){ 0

//.

};

链接后功能

使用后链接功能执行业务逻辑。在这个阶段,它已经知道它的所有子指令已经被编译,并且前链接和后链接功能已经被执行。

这就是为什么写业务逻辑代码被认为是最安全和默认的。

范围实例和元素实例作为参数传递给链接后函数:

以下是该函数的外观:复制代码如下:/* * *链接后函数* * @ param scope-与此历史关联的作用域* @ param ielem-instance element * @ param iAttrs-实例元素的属性*/函数(scope,iElem,iAttrs){ 0

//.

};

摘要

现在,您应该对编译、链接前和链接后之间的区别有了清晰的了解。

如果不是,并且你是一个严肃的ng开发者,那么我强烈建议你再次阅读这篇文章,直到你理解它

理解这些概念非常重要,可以帮助你理解ng原生指令的工作原理,优化自己的自定义指令。

如果有任何问题,请将您的问题添加到下面的评论中

今后,我们将继续分析指令:中的另外两个问题

1.使用transclusion属性的指令是如何工作的?2.指令的控制器功能是如何关联的

最后,如果你发现这篇文章有什么问题,请及时给我评论

谢谢你

版权声明:angularjs命令中编译和链接函数的详细说明是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。