簡體   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