繁体   English   中英

AngularJS:$ observe和$ watch方法之间的区别

[英]AngularJS : Difference between the $observe and $watch methods

我知道AngularJS中$scope中的某些更改会立即计算WatchersObservers 但是无法理解两者之间到底有什么区别。

我最初的理解是, Observers是针对角度表达式计算的,这些角度表达式是HTML端的条件,在Watchers执行$scope.$watch()函数时执行。 我的想法是否正确?

$ observe()Attributes对象上的一种方法,因此,它只能用于观察/监视DOM属性的值更改。 仅用于/调用内部指令。 当需要观察/观察包含插值的DOM属性(即{{}})时,请使用$ observe。
例如, attr1="Name: {{name}}" ,然后在指令中: attrs.$observe('attr1', ...)
(如果尝试使用scope.$watch(attrs.attr1, ...) ,则由于{{}}而无法正常工作-您将无法undefined 。)将$ watch用于其他所有内容。

$ watch()更复杂。 它可以观察/观察“表达式”,其中表达式可以是函数或字符串。 如果表达式是字符串,则将$ parse'd (即,作为Angular表达式求值)放入函数中。 (每个摘要周期都会调用此函数。)字符串表达式不能包含{{}}。 $ watch是Scope对象上的一种方法,因此可以在任何有权访问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获得字符串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表达式的信息。

如果我对您的问题理解正确,那么您在问,如果您使用$watch注册监听器回调,或者如果您使用$observe监听,那有什么区别。

执行$digest时会触发在$watch注册的回调。

当包含插值的属性(例如attr="{{notJetInterpolated}}" )的值发生更改时,将调用$observe注册的回调。


内部指令可以以非常相似的方式使用它们:

    attrs.$observe('attrYouWatch', function() {
         // body
    });

要么

    scope.$watch(attrs['attrYouWatch'], function() {
         // body
    });

我认为这很明显:

  • $ observe用于指令的链接功能。
  • $ watch用于观察值的任何变化。

请记住 :这两个函数都有两个参数,

$observe/$watch(value : string, callback : function);
  • value :始终是对监视元素的字符串引用(范围变量的名称或要监视的指令属性的名称)
  • callback :表单function (oldValue, newValue)要执行的function (oldValue, newValue)

我制造了一个塞子 ,因此您实际上可以了解它们的利用率。 我使用了变色龙类比,以使其更容易描绘。

为什么$ observe与$ watch不同?

评估watchExpression并将其与每个digest()周期的前一个值进行比较,如果watchExpression值发生变化,则会调用watch函数。

$ observe专门用于监视插值。 如果插入指令的属性值,例如dir-attr="{{ scopeVar }}" ,则仅在设置了插入值时(因此,在$ digest已经确定需要进行更新时),将调用observe函数。 基本上,已经有一个插值的监视程序,并且$ observe函数支持此操作。

请参见compile.js中的 $ observe和$ set

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM