我知道只要Watchers
中的某些内容在AngularJS中发生变化,就会计算Observers
和$scope
。但无法理解两者之间究竟有什么区别。
我最初的理解是Observers
是针对角度表达式计算的,这些条件是HTML端的条件,执行Watchers
函数时执行$scope.$watch()
。我在想什么?
答案 0 :(得分:604)
$observe() 是Attributes对象上的一种方法,因此,它只能用于观察/观察DOM属性的值更改。它仅在指令内使用/调用。需要观察/观察包含插值的DOM属性时使用$ observe(即{{}})。
例如,attr1="Name: {{name}}"
,然后在指令中:attrs.$observe('attr1', ...)
。
(如果你尝试scope.$watch(attrs.attr1, ...)
它会因{{}}而无效 - 你将获得undefined
。)使用$ watch来获取其他所有内容。
$watch() 更复杂。它可以观察/观察“表达式”,其中表达式可以是函数或字符串。如果表达式是一个字符串,则它是$parse'd(即,被评估为Angular expression)到函数中。 (每个摘要周期都会调用此函数。)字符串表达式不能包含{{}}。 $ watch是Scope对象上的一个方法,因此可以在任何有权访问范围对象的地方使用/调用它,因此在
中因为字符串被评估为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属性(即{{}})。 (它与$ watch一起使用的原因是因为'@'语法为我们执行interpolation,因此$ watch会看到没有{{}}的字符串。)为了更容易记住在哪个时使用,我建议在这种情况下使用$ observe。
为了帮助测试所有这些,我写了一个Plunker来定义两个指令。一个(d1
)不创建新范围,另一个(d2
)创建隔离范围。每个指令具有相同的六个属性。每个属性都是$ observe'd和$ watch'ed。
<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'"
attr5="a_string" attr6="{{1+aNumber}}"></div>
查看控制台日志,查看链接函数中$ observe和$ watch之间的差异。然后单击该链接,查看由Click处理程序进行的属性更改触发了哪些$ observes和$ watches。
请注意,当链接函数运行时,任何包含{{}}的属性都不会被评估(因此,如果您尝试检查属性,则会得到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表达式。
答案 1 :(得分:23)
如果我理解你的问题是正确的,那么如果你使用$watch
注册听众回调,或者如果你使用$observe
注册,那么你会问有什么不同。
执行$watch
时会触发注册$digest
的回调。
当包含插值的属性(例如$observe
)的值更改时,将调用向attr="{{notJetInterpolated}}"
注册的回调。
Inside指令你可以用非常相似的方式使用它们:
attrs.$observe('attrYouWatch', function() {
// body
});
或
scope.$watch(attrs['attrYouWatch'], function() {
// body
});
答案 2 :(得分:1)
我认为这很明显:
请记住:这个函数都有两个参数,
$observe/$watch(value : string, callback : function);
function (oldValue, newValue)
我已经制作了plunker,所以你可以真正掌握它们的利用率。我使用了Chameleon的比喻,以便更容易想象。
答案 3 :(得分:0)
为什么$观察与$ watch不同?
对watchExpression进行求值并与每个摘要()循环的前一个值进行比较,如果watchExpression值发生变化,则会调用watch函数。
$ observe特定于观察插值。如果对指令的属性值进行插值,例如dir-attr="{{ scopeVar }}"
,则只有在设置插值时才会调用observe函数(因此当$ digest已经确定需要进行更新时)。基本上已经有一个用于插值的观察器,$ observe函数可以捎带它。
参见$ observe&amp;在compile.js
中设置$