具有隔离范围的指令更复杂 . 如果使用'@'语法,你可以$ observe或$ watch一个包含插值的DOM属性(即{{}} 's). (The reason it works with $watch is because the ' @'语法对我们来说是interpolation,因此$ watch会看到没有{{}}的字符串 . )为了更容易记住何时使用,我建议在这种情况下使用$ observe .
为了帮助测试所有这些,我编写了一个定义两个指令的Plunker . 一个( d1 )不创建新范围,另一个( d2 )创建隔离范围 . 每个指令具有相同的六个属性 . 每个属性都是$ observe 'd and $watch' ed .
请注意,当链接函数运行时,包含{{}} 's are not evaluated yet (so if you try to examine the attributes, you' ll的任何属性都会得到 undefined ) . 查看插值的唯一方法是使用$ observe(如果使用带有'@'的隔离范围,则使用$ watch) . 因此,获取这些属性的值是异步操作 . (这就是为什么我们需要$ observe和$ watch函数 . )
4 回答
$observe() 是Attributes对象上的方法,因此,它只能用于观察/观察DOM属性的值更改 . 它仅在指令内使用/调用 . 需要观察/观察包含插值的DOM属性时使用$ observe(即{{}}) .
例如,
attr1="Name: {{name}}"
,然后在指令中:attrs.$observe('attr1', ...)
.(如果你试试
scope.$watch(attrs.attr1, ...)
它赢了't work because of the {{}}s -- you' ll得到undefined
. )使用$ watch获取其他所有内容 .$watch() 更复杂 . 它可以观察/观察"expression",其中表达式可以是函数或字符串 . 如果表达式是一个字符串,则它是$parse'd(即,被评估为Angular expression)到函数中 . (每个摘要周期都会调用此函数 . )字符串表达式不能包含{{}} . $ watch是Scope对象上的一个方法,因此可以在有权访问范围对象的任何地方使用/调用它,因此
控制器 - 任何控制器 - 通过ng-view,ng-controller或指令控制器创建的控制器
指令中的链接函数,因为它也可以访问范围
因为字符串被评估为Angular表达式,所以当您想要观察/观察模型/范围属性时,通常会使用$ watch . 例如,
attr1="myModel.some_prop"
,然后在控制器或链接功能中:scope.$watch('myModel.some_prop', ...)
或scope.$watch(attrs.attr1, ...)
(或scope.$watch(attrs['attr1'], ...)
) .(如果你试试
attrs.$observe('attr1')
,你会得到字符串myModel.some_prop
,这可能不是你想要的 . )正如在@ PrimosK的答案评论中所讨论的那样,每个digest cycle都会检查所有$ observes和$ watch .
具有隔离范围的指令更复杂 . 如果使用'@'语法,你可以$ observe或$ watch一个包含插值的DOM属性(即{{}} 's). (The reason it works with $watch is because the ' @'语法对我们来说是interpolation,因此$ watch会看到没有{{}}的字符串 . )为了更容易记住何时使用,我建议在这种情况下使用$ observe .
为了帮助测试所有这些,我编写了一个定义两个指令的Plunker . 一个(
d1
)不创建新范围,另一个(d2
)创建隔离范围 . 每个指令具有相同的六个属性 . 每个属性都是$ observe 'd and $watch' ed .查看控制台日志以查看链接函数中$ observe和$ watch之间的差异 . 然后单击该链接,查看由Click处理程序进行的属性更改触发的$ observes和$ watches .
请注意,当链接函数运行时,包含{{}} 's are not evaluated yet (so if you try to examine the attributes, you' ll的任何属性都会得到
undefined
) . 查看插值的唯一方法是使用$ observe(如果使用带有'@'的隔离范围,则使用$ watch) . 因此,获取这些属性的值是异步操作 . (这就是为什么我们需要$ observe和$ watch函数 . )有时你不需要$ observe或$ watch . 例如,如果您的属性包含数字或布尔值(不是字符串),只需评估一次:
attr1="22"
,然后在您的链接函数中:var count = scope.$eval(attrs.attr1)
. 如果它只是一个常量字符串 -attr1="my string"
- 那么只需在你的指令中使用attrs.attr1
(不需要$ eval()) .另见Vojta's google group post关于$ watch表达式 .
如果我理解你的问题是正确的,那么如果你用
$watch
注册监听器回调或者如果你用$observe
注册,那么你会问有什么区别 .执行
$digest
时,将触发$watch
注册的回调 .当包含插值的属性的值更改(例如
attr="{{notJetInterpolated}}"
)时,将调用$observe
注册的回调 .在内部指令中,您可以以非常类似的方式使用它们:
要么
我认为这很明显:
$ observe用于链接指令的功能 .
$ watch用于范围以观察其值的任何变化 .
请记住:这个函数都有两个参数,
value :始终是对被监视元素的字符串引用(要监视的范围's variable or the name of the directive' s属性的名称)
callback :表单执行的函数
function (oldValue, newValue)
我已经制作了一个plunker,所以你实际上可以掌握它们的利用率 . 我使用了变色龙的类比,以便更容易拍照 .
为什么$观察与$ watch不同?
对watchExpression进行求值并与每个摘要()循环的前一个值进行比较,如果watchExpression值发生变化,则调用watch函数 .
$ observe特定于观察插值 . 如果对指令的属性值进行插值,例如
dir-attr="{{ scopeVar }}"
,则只有在设置插值时才会调用observe函数(因此当$ digest已经确定需要进行更新时) . 基本上已经有一个用于插值的观察器,$ observe函数可以捎带它 .请参阅compile.js中的$ observe&$ set