Answers:
$ observe()是 Attributes对象上的一种方法,因此,它只能用于观察/监视DOM属性的值更改。仅用于/调用内部指令。需要观察/观察包含插值的DOM属性(即{{}})时,请使用$ observe。
例如,attr1="Name: {{name}}"
然后在指令中:attrs.$observe('attr1', ...)
。
(如果您尝试scope.$watch(attrs.attr1, ...)
使用{{}},它将无法工作-您将得到undefined
。)将$ watch用于其他所有内容。
$ watch()更复杂。它可以观察/观察“表达式”,其中表达式可以是函数或字符串。如果表达式是字符串,则将 $ parse'd(即,作为 Angular表达式求值)放入函数中。(每个摘要周期都会调用此函数。)字符串表达式不能包含{{}}。$ watch是 Scope对象上的一种方法,因此可以在任何有权访问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答案的评论所讨论的,每个摘要周期都会检查所有$ observes和$ watches 。
具有单独作用域的指令更加复杂。如果使用'@'语法,则可以$ observ 或$ watch包含插值(即{{}})的DOM属性。(它与$ watch一起使用的原因是因为'@'语法为我们进行了插值,因此$ watch看到的字符串中没有{{}}。)为了更容易记住何时使用哪个字符串,我建议使用$在这种情况下也要观察。
为了帮助测试所有这些,我编写了一个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之间的区别。然后单击链接,查看单击处理程序进行的属性更改触发了哪些$ observes和$ watches。
请注意,当链接功能运行时,尚未评估任何包含{{}}的属性(因此,如果您尝试检查这些属性,则会得到undefined
)。查看插值的唯一方法是使用$ observe(如果使用带'@'的隔离范围,则使用$ watch)。因此,获取这些属性的值是异步操作。(这就是为什么我们需要$ observe和$ watch函数。)
有时您不需要$ observe或$ watch。例如,如果您的属性包含数字或布尔值(不是字符串),则只需对其进行一次评估:attr1="22"
,然后在您的链接函数:中进行评估var count = scope.$eval(attrs.attr1)
。如果它只是一个常量字符串– attr1="my string"
则只需attrs.attr1
在您的指令中使用(不需要$ eval())。
另请参见Vojta在Google网上论坛上发布的有关$ watch表达式的信息。
ng-src/ng-href
使用attr.$observe
而不是scope.$watch
?
@
语法时它们可以互换。我相信没有性能差异(但是我没有查看实际的源代码)。
如果我正确理解了您的问题,那么您在问,如果使用注册注册侦听器回调$watch
或使用进行注册,有什么区别$observe
。
执行$watch
时触发向注册的回调$digest
。
$observe
当包含插值的属性的值更改时(例如attr="{{notJetInterpolated}}"
),将调用注册到的回调。
内部指令可以以非常相似的方式使用它们:
attrs.$observe('attrYouWatch', function() {
// body
});
要么
scope.$watch(attrs['attrYouWatch'], function() {
// body
});
$digest
,因此可以安全地假设将在中$observe
调用回调$digest
。并且$watch
回调也会被调用,$digest
但是每当值改变时。我认为他们做的完全一样:“观察表达式,调用回调值的更改”。关键字差异可能只是语法糖,不会使开发人员感到困惑。
我认为这很明显:
请记住:这两个函数都有两个参数,
$observe/$watch(value : string, callback : function);
function (oldValue, newValue)
我已经做了一个plunker,所以您实际上可以了解它们的利用率。我使用了变色龙类比,以使其更容易描绘。
为什么$ observe与$ watch不同?
评估watchExpression并将其与每个digest()周期的前一个值进行比较,如果watchExpression值发生变化,则会调用watch函数。
$ observe专门用于监视插值。如果插入指令的属性值,例如dir-attr="{{ scopeVar }}"
,则仅在设置了插入值时(因此,在$ digest已确定需要进行更新时),将调用watch函数。基本上,已经有一个插值的监视程序,并且$ observe函数支持此操作。
请参见compile.js中的 $ observe和$ set