AngularJS:$ observe和$ watch方法之间的区别
我知道,只要AngularJS中$scope
某些内容发生变化,Watcher和Observers
被计算出来。 但是不明白这两者之间究竟有什么区别。
我最初的理解是Observers
被计算为angular度expression式,这是HTML端的条件,当$scope.$watch()
函数被执行时, Watchers
被执行。 我是否正确思考?
$ observe()是Attributes对象上的一个方法,因此它只能用于观察/观察DOM属性的值更改。 它只用于/叫内部指令。 当需要观察/观察包含插值的DOM属性(即{{}})时,请使用$ observe。
例如, attr1="Name: {{name}}"
,然后在一个指令中: attrs.$observe('attr1', ...)
。
(如果你尝试使用scope.$watch(attrs.attr1, ...)
,它将不会工作,因为{{}} – 你会得到undefined
。)使用$ watch scope.$watch(attrs.attr1, ...)
其他事情。
$ watch()更复杂。 它可以观察/观察“expression式”,其中expression式可以是函数或string。 如果expression式是一个string,则它是$ parse'd (即,作为一个Angularexpression式求值)到一个函数中。 (这个函数被称为每个摘要循环。)stringexpression式不能包含{{}}。 $ watch是Scope对象的一个方法,所以只要你有权访问一个scope对象,就可以使用它
- 一个控制器 – 任何控制器 – 一个通过ng-view,ng-controller或一个指令控制器创build的控制器
- 一个指令中的链接函数,因为它也可以访问范围
因为string被评估为Angularexpression式,所以当你想要观察/观察一个模型/范围属性时,经常使用$ watch。 例如, attr1="myModel.some_prop"
,然后在控制器或链接函数中: scope.$watch('myModel.some_prop', ...)
或scope.$watch(attrs.attr1, ...)
(或scope.$watch(attrs['attr1'], ...)
)。
(如果你尝试attrs.$observe('attr1')
你会得到stringmyModel.some_prop
,这可能不是你想要的。)
正如@ PrimosK的回答中所讨论的那样,每个摘要周期都会检查所有$ observes和$ watch。
隔离范围指令更复杂。 如果使用'@'语法,则可以$ observe 或$观察包含插值的DOM属性(即{{}})。 (与$ watch一起工作的原因是因为'@'语法为我们插值 ,因此$ watch会看到一个没有{{}}的string。)为了更容易记住使用什么时候,我build议使用$也观察这种情况。
为了帮助testing所有这些,我写了一个定义了两个指令的Plunker 。 一个( d1
)不创build一个新的范围,另一个( d2
)创build一个隔离范围。 每个指令具有相同的六个属性。 每个属性都是$ observe'd和$ watch'ed。
<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'" attr5="a_string" attr6="{{1+aNumber}}"></div>
查看控制台日志,查看链接function中$ observe和$ watch之间的差异。 然后点击链接,看看哪些$ observes和$ watch是由点击处理程序所做的属性更改触发的。
请注意,链接函数运行时,任何包含{{}}的属性都不会被评估(因此如果您尝试检查属性,则会得到undefined
的属性)。 查看插值的唯一方法是使用$ observe(或$ watch,如果使用隔离范围和'@')。 因此,获取这些属性的值是一个asynchronous操作。 (这就是为什么我们需要$ observe和$ watch函数。)
有时你不需要$观察或$手表。 例如,如果你的属性包含一个数字或一个布尔值(不是string),只需计算一次: attr1="22"
,然后在你的链接函数中: var count = scope.$eval(attrs.attr1)
。 如果它只是一个常量string – attr1="my string"
– 那么只需在你的指令中使用attrs.attr1
(不需要$ eval())。
另请参阅Vojta关于$ watchexpression式的google群组文章 。
如果我正确理解你的问题,你要问的是,如果你用$watch
注册监听器callback,或者你用$observe
做注册,
执行$digest
时会触发注册了$watch
callback函数。 请参阅文档了解更多信息。
当包含插值的属性的值更改(例如attr="{{notJetInterpolated}}"
)时,将调用注册到$observe
callback。
在内部指令中,你可以用非常相似的方式使用它们两个:
attrs.$observe('attrYouWatch', function() { // body });
要么
scope.$watch(attrs['attrYouWatch'], function() { // body });
我觉得这很明显:
- $ observe用于指令的链接function。
- $ watch用于范围内观察其值的任何变化。
请记住 :这个函数有两个参数,
$observe/$watch(value : string, callback : function);
- value :始终是对watched元素的string引用(作用域variables的名称或要监视的指令属性的名称)
- callback :要执行的
function (oldValue, newValue)
我做了一个笨蛋 ,所以你可以实际掌握它们的使用情况。 我已经使用了变色龙的比喻来使绘画更容易。