我知道在AngularJS中,一旦$scope中的某些东西发生变化,观察者和观察者就会被计算出来。但不明白两者到底有什么区别。
我最初的理解是,观察者是为angular表达式计算的,这些表达式是HTML端上的条件,当$scope.$watch()函数被执行时,观察者会被执行。我想得对吗?
我知道在AngularJS中,一旦$scope中的某些东西发生变化,观察者和观察者就会被计算出来。但不明白两者到底有什么区别。
我最初的理解是,观察者是为angular表达式计算的,这些表达式是HTML端上的条件,当$scope.$watch()函数被执行时,观察者会被执行。我想得对吗?
当前回答
为什么$observe和$watch不同?
在每个digest()循环中,对watchExpression进行计算并与前一个值进行比较,如果watchExpression值发生变化,则调用watch函数。
$observe专门用于观察插入的值。如果一个指令的属性值被插入,例如dir-attr="{{scopeVar}}",那么只有当插入的值被设置时(因此当$digest已经确定需要进行更新时),observe函数才会被调用。基本上已经有了一个用于插值的观察者,而$observe函数与之相连。
参见compile.js中的$observe & $set
其他回答
如果我理解你的问题,你是问什么是不同的,如果你注册监听器回调与$watch或如果你做它与$观察。
当执行$digest时,使用$watch注册的回调将被触发。
用$observe注册的回调函数在包含插值的属性值变化时被调用(例如attr="{{notJetInterpolated}}")。
内部指令你可以用非常相似的方式使用它们:
attrs.$observe('attrYouWatch', function() {
// body
});
or
scope.$watch(attrs['attrYouWatch'], function() {
// body
});
$observe() is a method on the Attributes object, and as such, it can only be used to observe/watch the value change of a DOM attribute. It is only used/called inside directives. Use $observe when you need to observe/watch a DOM attribute that contains interpolation (i.e., {{}}'s). E.g., attr1="Name: {{name}}", then in a directive: attrs.$observe('attr1', ...). (If you try scope.$watch(attrs.attr1, ...) it won't work because of the {{}}s -- you'll get undefined.) Use $watch for everything else.
$watch()更复杂。它可以观察/观察一个“表达式”,其中表达式可以是一个函数或字符串。如果表达式是一个字符串,它将被$parse - d(即,作为Angular表达式求值)转换为一个函数。(每个文摘周期都要调用这个函数。)字符串表达式不能包含{{}}。$watch是Scope对象上的一个方法,因此可以在任何可以访问Scope对象的地方使用/调用它,因此在
一个控制器——任何控制器——通过ng-view、ng-controller或指令控制器创建的控制器 指令中的链接函数,因为它也可以访问作用域
因为字符串是按Angular表达式计算的,所以当你想观察/观察一个model/scope属性时,通常会使用$watch。例如,myModel attr1 =”。然后在控制器或链接函数中:scope.$watch('myModel. some_prop ')。Some_prop ',…)或scope.$watch(attrs。Attr1,…)(或范围。看(attrs [' attr1美元 '], ...)). (如果你尝试attrs.$observe('attr1'),你会得到字符串myModel。Some_prop,这可能不是您想要的。)
正如在@PrimosK回答的评论中所讨论的那样,每个消化周期都会检查所有的$ observed和$watches。
具有独立作用域的指令更加复杂。如果使用'@'语法,您可以$observe或$watch包含插值(即{{}})的DOM属性。(它与$watch一起工作的原因是因为'@'语法为我们做了插值,因此$watch看到一个没有{{}}的字符串。)为了更容易记住何时使用哪个,我建议在这种情况下也使用$observe。
为了帮助测试所有这些,我编写了一个定义两个指令的Plunker。一个(d1)不创建新的作用域,另一个(d2)创建一个孤立的作用域。每个指令都有六个相同的属性。每个属性都是$ observed和$watch'ed。
<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'"
attr5="a_string" attr6="{{1+aNumber}}"></div>
查看控制台日志,查看链接函数中$observe和$watch之间的差异。然后单击链接,查看哪些$ observed和$watches是由单击处理程序所做的属性更改触发的。
请注意,当link函数运行时,任何包含{{}}的属性都不会被计算(因此,如果您尝试检查这些属性,您将得到undefined)。查看插值值的唯一方法是使用$observe(如果使用带有'@'的隔离作用域,则使用$watch)。因此,获取这些属性的值是一个异步操作。(这就是为什么我们需要$observe和$watch函数。)
有时你不需要$observe或$watch。例如,如果你的属性包含一个数字或布尔值(不是字符串),只计算一次:attr1="22",然后在你的链接函数:var count = scope.$eval(attrs.attr1)。如果它只是一个常量字符串- attr1="my string" -那么只使用attrs。Attr1在你的指令(不需要$eval())。
参见Vojta的谷歌组关于$watch表达式的帖子。
我认为这很明显:
$observe用于指令的链接函数。 $watch在scope上用于监视其值的任何变化。
记住:两个函数都有两个参数,
$observe/$watch(value : string, callback : function);
Value:始终是被监视元素的字符串引用(作用域变量的名称或要监视的指令属性的名称) 回调:要执行的函数形式为function (oldValue, newValue)
我做了一个活塞,这样你就可以了解它们的利用率。我用变色龙的比喻是为了更容易描绘。
为什么$observe和$watch不同?
在每个digest()循环中,对watchExpression进行计算并与前一个值进行比较,如果watchExpression值发生变化,则调用watch函数。
$observe专门用于观察插入的值。如果一个指令的属性值被插入,例如dir-attr="{{scopeVar}}",那么只有当插入的值被设置时(因此当$digest已经确定需要进行更新时),observe函数才会被调用。基本上已经有了一个用于插值的观察者,而$observe函数与之相连。
参见compile.js中的$observe & $set