对照地址:https://code.angularjs.org/1.5.8/docs/api/ng/service/$compile
$compile是将一个DOM字符串或者一个DOM进行编译并返回一个模板链接函数,这个链接函数可以用于将scope和模版链接到一起. 编译其实是个遍历DOM树,匹配和处理DOM上的各个指令的过程.
注意:这个篇文档将深入介绍指令的各种选项,如果只是想通过例子来简单了解指令,可以参考directive guide
全解指令API
对于一个指令来说有许多不同的选项。 不同点在于工厂函数的返回值。你既可以返回一个携带各个属性的指令定义对象,也可以只返回一个postLink 函数(这样一来,所有的属性都会使用默认值)。
最佳实践:推荐大家使用指令定义对象。
下面是个声明了指令定义对象的案例:
var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { priority: 0, template: '<div></div>', // or // function(tElement, tAttrs) { ... }, // or // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, transclude: false, restrict: 'A', templateNamespace: 'html', scope: false, controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, controllerAs: 'stringIdentifier', bindToController: false, require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } // or // return function postLink( ... ) { ... } }, // or // link: { // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, // post: function postLink(scope, iElement, iAttrs, controller) { ... } // } // or // link: function postLink( ... ) { ... } }; return directiveDefinitionObject; }); 注意:任何未指定的选项将会使用默认值。参见下面的默认值。上面的代码可以简化为:
var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { link: function postLink(scope, iElement, iAttrs) { ... } }; return directiveDefinitionObject; // or // return function postLink(scope, iElement, iAttrs) { ... } });(Life-cyle hooks)生命周期钩子
在一个指令的生命周期(Inject->Compile->Controller加载->pre-link->post-link->生成DOM)中,指令控制器可以提供下面的各个方法供Angular调用:
$onInit() - 当一个元素上所有控制器都被构造完毕和初始化绑定完毕之后,每个控制器都可以调用该方法(在这个元素所有的指令的pre & post link 阶段之前)。是控制器中放初始化代码的最好时机。
$onChanges(changeObj)- 单向绑定(<)或者插值绑定(@)被更新时调用。changeObj是一个哈希对象,其中key是已经更改的绑定属性的名称,value是当前对象{currentValue,previousValue,isFirstChange()}。使用这个钩子来触发一个组件的更新,比如克隆绑定的值,防止外部值突然更新。
$doCheck() - 每轮digest 循环时被调用。改变时提供一个入口来探测和执行。每个你希望根据这个改变做出响应的行为一旦被探测到,必须通过这个钩子被调用;$onChanges被调用时,此方法无效。例如,当你希望执行一个深度检查或者检查一个日期对象的改变,不会被Angular的"侦探"探测到也不会触发$onChanges,这个钩子将会变得非常有用。这个钩子调用时没有参数;如果监测到更新,你必须存储之前的值来跟当前的值进行比较。
$onDestroy() - 当控制器中包含的scope被销毁时调用。使用这个钩子来释放外部的资源,watch和事件处理。你需要注意的是对$scope来说组件有自己的$onDestroy() 钩子在同等级别可以被调用。$broadcast事件被触发时,是从上到下的。这就意味着父级组件将会调用己的$onDestroy() 钩子在子组件调用之前。
$postLink() - 控制器元素和子元素被linked之后被调用。和post-link 函数类似,这个钩子可以用来生成DOM事件处理程序和直接操作DOM结构。你需要注意的是子元素中如果已经包含templateUrl,指令不会被编译和链接,这是因为他们在等他们的模板异步加载同时他们自己的编译和链接已经被暂停。
和Angular2 生命周期比较 Angular2同样在组件中使用了一些钩子。虽然和1.x版本相似,但是有些地方应该注意,特别是把你代码从1.x版本升级到2.x版本的时候:
1.x版本钩子中前缀使用$,如$onInit。2.x钩子前缀改成了ng,如ngOnInit.1.x版本钩子可以在控制器的属性上定义或者在构造函数中添加。2.x版本中只允许在组件类的属性上定义钩子。由于change-detection的差异,1.x版本中的$doCheck比2.x版本的ngCheck调用的更多。$doCheck中的模型改变将会触发新一轮的digest循环,引起的改变将会贯穿整个应用传播。2.x版本则不允许ngDoCheck 钩子从组件外部触发改变。它既不会抛错误,也不取决于enableProdMode()的状态。Life-cycle hook examples 。。。
指令定义对象
指令定义对象给编译器提供指令的各个参数。参数如下:
multiElement
当此属性设置为true时,HTML编译器将收集指令属性开始和结束之间的DOM节点,并按组将他们结合在一起作为指令元素。建议此功能用于非严格行为(如ngClick),并且没有操作或替换子节点(如ngInclude)的情况下。
priority
当一个DOM元素中定义了多个指令,有时有必要指定指令执行的顺序。优先级是用来在它们的编译函数调用之前对指令进行排序的。优先级被定义为一个数字。具有更大的数值优先级的指令首先被编译。pre-link功能也按照优先级顺序执行,但Post-link功能是以相反的顺序执行的。相同优先级的指令的执行顺序是不确定的。默认优先级为0。
terminal
如果设置为真,那么当前的优先级将是最后执行,(当前优先级的任何指令仍将执行,因为未定义相同优先级的执行顺序)。请注意,指令模板中使用的表达式和其他指令也将从执行中排除。
scope 这个scope属性可以设置为true,对象或falsy值(与false相等的值):
falsy:不会为指令建立新的作用域,指令将使用父作用域.
true :一个原型继承自父作用域的子作用域将会被创建.如果一个DOM元素的多个指令都要求创建新的作用域,只有一个作用域会被创建.创建新作用域的规则不适用于模板的根节点,因为模板的根节点总是会得到一个新的作用域。
{…}(一个对象哈希):那么一个新的“孤立的”作用域就会被创建。这个“孤立的”作用域区别于正常作用域的地方在于,它不会以原型继承的方式直接继承自父作用域。这对于创建可重用的组件是非常有用的,因为可重用的组件一般不应该读或写父作用域的数据。 这个“孤立的”作用域使用一个对象哈希来表示,这个哈希定义了一系列本地作用域属性。这些本地属性对于模板的别名值非常有用。 对象哈希中的键映射到孤立作用域的属性; 值通过在指令的元素上匹配属性来定义属性如何绑定到父作用域:
@ 或 @attr - 将本地作用域成员和DOM属性绑定。绑定结果总是一个字符串,因为DOM的属性就是字符串。如果没有指定attr名称,那么默认和本地名称相同。举个例子:<my-component my-attr="hello {{name}}">和孤立作用域对象: scope:{localName:'@myAttr' } ,指令的scope属性localName将反映hello {{name}}的内插值。因为name属性改变了所以指令的scope上的localName属性也跟着改变了。 该name从父作用域(而不是指令的作用域)读取。= 或 =attr - 在本地作用域属性和父作用域属性间建立一个双向的绑定。表达式在父作用域的上下文中求值。如果未指定attr名称,则属性名称假定与本地名称相<my-component my-attr ="parentModel">作用域定义范围:{localModel:'= myAttr'},指令范围上的属性localModel将反映父范围上的parentModel的值。对parentModel的更改将反映在localModel中,反之亦然。可选属性应标记为带有问号:=?或=?attr。如果绑定表达式是不可分配的,或者如果属性不是可选的并且不存在,那么在发现对本地值的更改时将抛出异常($compile:nonassign),因为将无法同步到父作用域。默认情况下,$ watch方法用于跟踪更改,并且等价检查是基于对象标识。但是,如果一个对象字面量或一个数组字面量作为绑定表达式传递,则相等性检查由value完成(使用angular.equals函数)。还可以使用$watchCollection:use = *或= * attr(= *?或= *?attr,如果属性是可选的)来仔细观察评估值。
< 或 < attr - 在本地作用域属性和通过属性attr传递的表达式之间设置单向绑定。表达式在父作用域的上下文中求值。如果未指定attr名称,则属性名称假定与本地名称相同。您还可以通过添加?使绑定可选::<?或<?attr。例如,给<my-component my-attr =“parentModel”>和scope的指令定义:{localModel:'< myAttr'},则孤立的scope属性localModel将在父作用域上反映parentModel的值。对parentModel的任何更改都将反映在localModel中,但localModel中的更改将不会反映在parentModel中。但是有两个注意事项:
1.单向绑定不会将值从父复制到隔离范围,它只是设置相同的值。这意味着如果您的绑定值是一个对象,对其在孤立范围中的属性的更改将反映在父作用域中(因为两者都引用同一对象)。 2.单向绑定监视父值标识的改变。这意味着对父值的$ watch仅在对值的引用发生更改时触发。在大多数情况下,这不应该被关注,但是重要的是要知道如果您单向绑定到对象,然后替换该对象在孤立的范围。如果现在更改父作用域中对象的属性,则更改将不会传播到隔离的作用域,因为父作用域上的对象的标识未更改。相反,您必须分配一个新对象。
如果您不打算将您的隔离范围绑定的更改传播回父级,则单向绑定很有用。然而,他也没有使这个完全不可能实现。
& 或者 &attr:提供了一种执行父作用域下的表达式的方式.如果不指明attr,子作用域属性和dom元素的属性的名字将一致.给< my-component my-attr=“count = count + value”>和指令定义的作用域scope: { localFn:’&myAttr’ },那么孤立作用域属性localFn将指向一个函数,这个函数包装了count = count + value表达式.通常需要通过表达式将数据从孤立作用域的表达式传递到父作用域。 这可以通过将局部变量名和值的映射传递到表达式包装器fn中来完成。 例如,如果表达式是increment(amount),那么我们可以通过将localFn调用localFn({amount:22})来指定金额值。通常,可以对一个元素应用多个指令,但是根据指令所要求的范围类型,可能存在一些限制。 以下几点将有助于解释这些限制。 为了简单起见,仅考虑两个指令,但它也适用于几个指令:
no scope + no scope => 两个指令都没有要求自己的作用域,那么都会使用父作用域child scope + no scope => 会共享一个子作用域child scope + child scope => 会共享一个子作用域isolated scope + no scope => 前者使用"孤立"作用域,后者使用父作用域isolated scope + child scope =>不会正常工作,一个元素只能有一个scope.isolated scope + isolated scope => 不会正常工作,一个元素只能有一个scope.bindToController
此属性用于将scope属性直接绑定到控制器。 它可以是true或与scope属性具有相同格式的对象哈希。 此外,必须通过使用controllerAs:'myAlias’或通过在控制器定义中指定别名来设置控制器别名:controller:‘myCtrl as myAlias’。
当一个孤立scope用于指令(见上文)时,bindToController:true将允许一个组件的属性绑定到控制器,而不是scope。
控制器实例化后,孤立scope绑定的初始值将绑定到控制器属性。 你可以通过$ onInit的控制器方法访问这些绑定,在一个元素上的所有控制器都被构造并且它们的绑定被初始化之后。
弃用警告:虽然非ES6类控制器的绑定可以在调用控制器构造函数之前绑定到this,但现在已不推荐使用。 请在控制器上放置一个依赖于$ onInit方法中的绑定的初始化代码。
也可以将bindToController设置为与scope属性格式相同的对象哈希。 这将直接设置scope绑定到控制器。 请注意,scope仍然可以用于定义创建哪种类型的范围。 默认情况下,不创建scope。 使用scope:{}创建隔离范围(对组件指令有用)。
如果bindToController和scope都定义了并且有对象哈希,bindToController会覆盖scope。
controller
控制器构造函数。控制器在预链接阶段之前被实例化,并且可以被其他指令访问(参见require属性)。这允许指令彼此通信并增强彼此的行为。控制器可以注入下列参数(并支持括号):
$scope - 与元素关联的当前范围
$element - 当前元素
$attrs - 元素的当前属性对象
$transclude - 转换链接函数pre-bound到正确的转换scope: function([scope],cloneLinkingFn,futureParentElement,slotName):
* scope:(可选)重写scope。 * cloneLinkingFn:(可选)用于创建原始transclude内容的克隆。 * futureParentElement(可选): > 定义cloneLinkingFn将向其添加克隆元素的父级。 > default:$element.parent();$element for transclude:'element'; transclude:true。 >只需要允许包含非html元素(例如SVG元素)的transclude和cloneLinkinFn传递时,因为这些元素需要创建和克隆,当它们在常规容器外部定义时(例如像<svg> )。 >另请参见directive.templateNamespace属性。slotName:(可选)要嵌入的slot名称。如果falsy(例如null,undefined或’ '),则提供默认转换。 $ transclude函数也有一个方法,$ transclude.isSlotFilled(slotName),如果指定的slot包含内容(即一个或多个DOM节点)返回true。
require
请求另一个指令并注入该指令的控制器作为link函数的第四个参数。require属性可以是字符串,数组或者对象。
一个包含要传递给链接函数的指令名称的字符串一个包含要传递给链接函数的指令名称的数组。 传递给链接函数的参数将是一个与require属性中的名称顺序相同的控制器数组一个对象的属性值是要传递给链接函数的指令的名称。 传递给链接函数的参数也将是具有匹配键的对象,其值将保存相应的控制器。如果require属性是一个对象,并且bindToController是真,那么被包含的控制器将使用require属性的键绑定到控制器。 这个绑定发生在所有的控制器被构造之后,但$onInit被调用之前。 如果被包含的控制器的名称与本地名称(键)相同,则可以省略该名称。 例如,{parentDir:’^’}等价于{parentDir:’^ parentDir’}。 有关如何使用它的示例,请参阅$ compileProvider帮助。 如果没有找到这样的包含指令,或者如果指令没有控制器,会引发错误(除非没有指定链接功能,并且包含的控制器不绑定到指令控制器,在这种情况下 错误检查被跳过)。 名称可以带有的前缀为:
*(无前缀) - 在当前元素上找到所需的控制器。 如果找不到,则抛出错误。
? - 如果找不到,尝试找到所需的控制器或传递null到链接fn。^ - 通过搜索当前元素及其父元素找到所需的控制器。 如果找不到,则抛出错误。^^ - 通过搜索元素的父项找到所需的控制器。 如果找不到,则抛出错误。?^ - 尝试通过搜索当前元素及其父元素找到所需的控制器,如果找不到,则将null传递给链接fn。?^^ - 尝试通过搜索当前元素们的父元素找到所需的控制器,如果找不到,则将null传递给链接fn。controllerAs
指令的scope中对控制器的引用的标识符名称(给控制器取别名)。 这允许从指令模板引用控制器。 这在将指令用作组件(即使用孤立scope)时尤其有用。 也可以在没有孤立/新作用域的指令中使用它,但是您需要注意,controllerAs引用可能会覆盖父作用域上已存在的属性。
restrict
EACM(元素名称/属性/类名/注释)子集的字符串,用来限制指令的调用方式。 如果省略,则使用默认值(元素名称和属性)。
E - Element name (default): A - Attribute (default): C - Class: M - Comment:templateNamespace
表示模板中标记使用的文档类型的字符串。 AngularJS需要这些信息,当它们被定义在它们通常的容器之外,例如 和的时候,这些元素需要以特殊的方式创建和克隆。
html - 模板中的所有根节点都是HTML。 根节点也可以是顶级元素,例如 或。 svg - 模板中的根节点是SVG元素(不包括)。math - 模板中的根节点是MathML元素(不包括 )。如果没有指定templateNamespace,那么命名空间被认为是html。
template
HTML标记可以是:
替换指令的元素的内容(默认)。替换指令的元素本身(如果replace为true - DEPRECATED(过时的))。包含指令的元素的内容(如果transclude为true)。值可能是:
字符串,例如<div red-on-hover> {{delete_str}} </ div>。一个函数,它接受两个参数tElement和tAttrs(在下面的编译函数api中描述),并返回一个字符串值。templateUrl
这与模板类似,但模板是从指定的URL异步加载的(类似于load())。
因为模板加载是异步的,编译器将暂停对该元素的指令编译,直到模板被解析时。同时,它将继续编译和链接兄弟元素和父元素,就好像这个元素没有包含任何指令。
编译器不会暂停整个编译器来等待加载模板,因为这会导致整个应用程序“停滞”,直到所有模板都被异步加载 - 即使在只有一个深层嵌套指令具有templateUrl的情况下。 模板加载是异步的,即使模板已预装入$templateCache 您可以将templateUrl指定为表示URL的字符串,或者作为一个函数,它接受两个参数tElement和tAttrs(在下面的编译函数api中描述),并返回一个表示url的字符串值。在这两种情况下,模板URL都通过$ sce.getTrustedResourceUrl传递。
replace([DEPRECATED!],将在下一个主要版本中移除 - 即v2.0)
指定模板应该替换什么。 默认为false。
true - 模板将替换指令的元素。false - 模板将替换指令的元素的内容。替换过程将所有属性/类从旧元素迁移到新元素。 有关示例,请参见指令指南。
有一些很少的场景,其中元素替换是需要的应用程序功能,主要是可重复使用的自定义组件,在SVG上下文中使用(因为SVG不能使用DOM树中的自定义元素)。
transclude
提取指令出现的元素的内容,并使其可用于指令。 内容被编译之后作为transclusion函数提供给指令。 请参阅下面的“Transclusion”部分。
compile
function compile(tElement,tAttrs,transclude){...}编译函数处理转换模板DOM。因为大多数指令不做模板变换,所以不经常使用。编译函数接受以下参数:
tElement - template element - 声明指令的元素。仅在元素和子元素上进行模板转换是安全的。
tAttrs - 模板属性 - 在所有指令编译函数之间共享的此元素上声明的属性列表。
transclude - [DEPRECATED!]一个transclude链接函数:function(scope,cloneLinkingFn)
注意:如果模板已克隆,模板实例和链接实例可能是不同的对象。因此,除了适用于编译函数中所有克隆的DOM节点的DOM转换之外,做其他任何事情都是不安全的。具体来说,DOM监听注册应该在链接函数中完成,而不是在编译函数中完成。
注意:编译函数不能处理在自己的模板或编译函数中递归使用自身的指令。编译这些指令会导致无限循环和堆栈溢出错误。这可以通过在postLink函数中手动使用$ compile来强制编译指令的模板而不是依赖于通过模板或templateUrl声明的自动模板编译或在编译函数内的手动编译来避免。
注意:传递给compile函数的transclude函数已被弃用,因为它不知道正确的外部scope。请使用传递给链接函数的transclude函数替代。
编译函数可以有一个返回值,它可以是一个函数或一个对象。
返回(post-link)函数 - 等价于当编译函数为空时通过config对象的link属性注册的链接函数。
返回具有通过pre和post属性注册的函数的对象 - 允许您控制何时在链接阶段调用链接函数。请参阅下面的有关pre-linking和post-linking功能的信息。
link
仅当未定义compile属性时才使用此属性。(即不能和compile同时使用)
function link(scope,iElement,iAttrs,controller,transcludeFn){...}链接功能负责注册DOM监听器以及更新DOM。它在克隆了模板之后才被执行。大多数指令中处理业务逻辑的地方。
scope - Scope - 指令用于注册watches(监听)。
iElement - 实例化元素 - 即要使用指令的元素。仅在postLink函数中操作元素的子元素是安全的,因为子元素已经被链接。
iAttrs - 实例属性 - 在所有指令链接函数之间共享的此元素上声明的属性列表。
控制器 - 被require指令的控制器实例 - 实例在所有指令之间共享,允许指令使用控制器作为通信方式。确切的值取决于指令的require属性:
不需要控制器:指令自己的控制器,如果没有控制器,则为未定义string:控制器实例array:控制器实例数组 如果无法找到require的控制器,并且它是可选的,则该实例为null,否则抛出Missing Required Controller错误。注意,你也可以require指令自己的控制器 - 就和任何其他控制器一样可用。
transcludeFn - 预先绑定到正确的转换范围的转换链接函数。这与指令控制器的$transclude参数相同,有关详细信息,请参阅控制器部分。function([scope],cloneLinkingFn,futureParentElement)。Pre-linking function
子元素被链接前执行的函数。做DOM转换是不安全的,因为编译器链接函数将无法定位到正确的链接元素。
Post-linking function
在子元素链接后执行。 请注意,包含templateUrl指令的子元素将不会被编译和链接,因为它们正在等待模板异步加载,并且其自身的编译和链接已暂停,直到加载完毕。
在不等待其异步模板被解析的元素上的post-linking 函数中进行DOM转换是安全的。
Transclusion
嵌入是从DOM的一部分提取DOM元素的集合并将它们复制到DOM的另一部分,同时保持它们与它们被取得的原始AngularJ scope的连接的过程。 (听起来比较绕口,其实跟克隆(true)差不多意思) transclusion被用来(通常使用ngTransclude)将指令的元素的原始内容插入指令模板中的指定位置。 好处是,通过简单地手动移动DOM元素,被转换的内容可以访问到被接收的scope上的属性,即使该指令具有孤立的scope。 请参阅指令指南。
这使得窗口小部件可以具有其模板的私有状态,而被transclude的内容可以访问其原始scope。
注意:测试元素transclude指令时,不能将指令放置在正在编译的DOM根片段。 请参阅测试Transclusion指令。
有三种类型的嵌入方式,取决于你是否只需transclude指令的元素的内容,整个元素或元素内容的多个部分:
true - 嵌入指令的元素的内容(即子节点)。‘element’ - 嵌入整个指令的元素,包括以比此指令低的优先级定义的该元素上的任何指令。使用时,将忽略模板属性。{…}(对象哈希): - 将内容的元素映射到模板中的“slots”。通过为transclude属性提供一个对象来声明Mult-slot transclusion 。
此对象是一个映射,其中键是要填充的slot的名称,值是用于将HTML与slot匹配的元素选择器。元素选择器应该是标准化形式(例如myElement),并且将匹配标准元素变形(例如my-element,my:element,data-my-element等)。(ng中js端的驼峰等价于页面上的折线连接方式)
有关详细信息,请参阅匹配指令指南
如果元素选择器前缀有?那么该slot是可选的。
例如,transclude对象{slotA:'?myCustomElement'}将<my-custom-element>元素映射到slotAslot,可以通过$ transclude函数或通过ngTransclude指令访问。
未标记为可选(?)的slot将在transclude内容中没有匹配的元素时触发编译时错误。如果你想知道一个可选的slot是否填充了内容,你可以调用$ transclude.isSlotFilled(slotName)在transclude函数传递给指令的链接函数,并注入到指令的控制器。
Transclusion Functions
当指令请求transclusion时,编译器提取其内容并向指令的链接函数和控制器提供转换函数。这个转换函数是一个特殊的链接函数,它将返回链接到新的转换scope的编译内容。
如果你只是使用ngTransclude,那么你不需要担心这个函数,因为ngTransclude会为我们处理它。
如果要手动控制在指令中插入和删除嵌入内容,则必须使用此函数。当调用transclude函数时,它返回一个包含编译的DOM的jqLite / JQuery对象,该对象链接到正确的转换范围。
当你调用一个transclusion函数,你可以传入一个克隆附加功能。此函数接受两个参数function(clone,scope){…},其中克隆是转录内容的新编译副本,scope是克隆绑定到的新创建的转换scope。
最佳实践:当您调用转录函数时,始终提供cloneFn(克隆附加函数),因为您将获得原始DOM的新克隆,并且还可以访问新的转换scope
通常的做法是将您的嵌入内容(克隆)附加到克隆附件函数中的DOM中:
var transcludedContent,transclusionScope; $ transclude(function(clone,scope){ element.append(clone); transcludedContent = clone; transclusionScope = scope; });之后,如果你想从你的DOM中删除嵌入的内容,那么你也应该销毁相关的嵌入scope:
transcludedContent.remove(); transclusionScope.$destroy();最佳实践:如果您打算在您的指令中手动添加和删除转录的内容(通过调用transclude函数获取DOM并调用element.remove()来删除它),那么您还得负责在transclusion scope上调用$destroy.
内置的DOM操作指令,如ngIf,ngSwitch和ngRepeat会根据需要自动破坏它们的嵌入克隆,所以如果你只是简单地使用ngTransclude将转换注入你的指令则不需要担心。
Transclusion Scopes
当你调用一个transclude函数时,它返回一个预先绑定到transclusion scope 的一个DOM的片段。 这个scope是特殊的,因为它是指令scope的一个子节点(当指令的scope被销毁时也会被销毁),但它继承了被引用的scope的属性。
例如,一个使用transclusion 和孤立作用域的指令。 DOM层次结构可能如下所示:
<div ng-app> <div isolate> <div transclusion> </div> </div> </div>其父级作用域层次结构将如下所示:
- $rootScope - isolate - transclusion但是作用域将从他们的父级的不同作用域原型继承。
- $rootScope - transclusion - isolateAttributes
Attributes对象 - 作为link()或compile()函数中的参数传递。它有多种用途。
访问符合规范的属性名称:诸如’ngBind’之类的指令可以用许多方式表示:‘ng:bind’,data-ng-bind或’x-ng-bind’。属性对象允许对属性的规范化访问。
指令互通:所有指令共享属性对象的相同实例,允许指令使用属性对象作为互通指令通信。
支持插值:插值属性分配给属性对象,允许其他指令读取插值。(插值==新增的属性)
观察内插属性:使用$ observe观察包含内插的属性的值更改(例如src =“{{bar}}”)。这不仅是非常有效的,而且它也是容易获得实际值的唯一方法,因为在链接阶段期间内插尚未被激活,因此该值被设置为未定义。
function linkingFn(scope, elm, attrs, ctrl) { // get the attribute value console.log(attrs.ngModel); // change the attribute attrs.$set('ngModel', 'new value'); // observe changes to interpolated attribute attrs.$observe('ngModel', function(value) { console.log('ngModel has changed value to ' + value); }); }案例 注意:通常,指令使用module.directive注册。 下面的例子是说明$ compile是如何工作的。
。。。。。。
完毕~有些地方不知道该如何表达,有不同意见的欢迎指正。