2013-02-14 63 views
359

我知道,無論WatchersObservers就將計算的東西在AngularJS $scope變化。但不明白這兩者之間究竟有什麼區別。

我最初的理解是,Observers計算爲角表達式這些都對其中作爲執行Watchers當執行$scope.$watch()功能的HTML側條件。我在想什麼?

+1

你的編輯沒有幫助,有點拮抗。請體諒其他人來這裏尋求實際幫助。 – smalone 2016-08-17 02:01:36

+0

@smalone改變了。感謝和抱歉! – Abilash 2016-08-22 08:13:27

+0

不用擔心。感謝您的修復。 – smalone 2016-09-15 18:21:30

回答

587

$observe()Attributes對象的方法,因此,它只能用於觀察/觀察DOM屬性的值更改。它只用於/叫做內部指令。當您需要觀察/觀看包含插值的DOM屬性(即{{}})時,請使用$ observe。
例如,attr1="Name: {{name}}",然後在指令中:attrs.$observe('attr1', ...)
(如果您嘗試使用scope.$watch(attrs.attr1, ...),則{{}}將不起作用 - 您將獲得undefined。)使用$ watch查看其他所有內容。

$watch()比較複雜。它可以觀察/觀察「表達式」,其中表達式可以是函數或字符串。如果該表達式是一個字符串,則它是$parse'd(即,被評估爲Angular expression)到一個函數中。 (這個函數被稱爲每個摘要循環。)字符串表達式不能包含{{}}。 $表是Scope對象上的方法,所以它可以用於/被叫無論你可以使用一個範圍對象,因此,在

  • 控制器 - 任何控制器 - 一個通過NG-視圖,納克創建-controller,或指令控制器
  • 在指令的連接功能,因爲這有訪問範圍以及

因爲字符串作爲角表達式求值,當你想觀察$腕錶經常使用/觀看模型/範圍屬性。例如,attr1="myModel.some_prop",然後在控制器或鏈接功能中:scope.$watch('myModel.some_prop', ...)scope.$watch(attrs.attr1, ...)(或scope.$watch(attrs['attr1'], ...))。
(如果你嘗試attrs.$observe('attr1'),你會得到字符串myModel.some_prop,這可能不是你想要的。)

正如對@PrimosK的回答評論所述,所有$觀察和$手錶都檢查每digest cycle

隔離範圍的指令更復雜。如果使用'@'語法,您可以$觀察或$ watch一個包含插值(即{{}})的DOM屬性。 (它與$ watch一起工作的原因是因爲'@'語法對我們來說是interpolation,因此$ 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和$ watch是由點擊處理程序所做的屬性更改觸發的。

請注意,當鏈接函數運行時,任何包含{{}}的屬性都不會被評估(因此如果您嘗試檢查屬性,則會得到undefined)。查看插值的唯一方法是使用$ observe(或者如果使用'@'隔離範圍,則使用$ watch)。因此,獲取這些屬性的值是異步操作。 (這就是爲什麼我們需要$觀察和$手錶的功能。)

有時你不需要$ observe或$ watch。例如,如果你的屬性包含一個數字或一個布爾值(不是字符串),只需評估一次:attr1="22",然後在你的鏈接函數中:var count = scope.$eval(attrs.attr1)。如果它只是一個常量字符串– attr1="my string" –那麼只需在您的指令中使用attrs.attr1(不需要$ eval())。

另請參閱Vojta's google group post約$ watch表達式。

+12

很好的解釋! +1 – PrimosK 2013-02-22 21:35:56

+51

這比官方的Angular文檔更有用!謝謝! – 2013-05-15 23:09:54

+4

很好的答案!你知道爲什麼'ng-src/ng-href'使用'attr。$ observe'而不是'scope。$ watch'呢? – okm 2013-05-21 10:17:26

20

如果我理解你的問題,你問的是什麼是如果你註冊聽衆回撥$watch或如果你這樣做$observe

當執行$digest時,會觸發註冊爲$watch的回調。請參閱docs瞭解更多信息。

當包含插值的屬性的值更改(例如attr="{{notJetInterpolated}}")時,將調用註冊爲$observe的回調。


內部指令,你可以使用這兩者非常相似的方式:

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

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

其實,因爲每一個變化都會反映在'$ digest'階段,所以'$ digest'回調將被安全地假定'$ digest'中被調用。 '$ digest'中也會調用'$ watch'回調函數,但每當值被更改時。我認爲他們完成同樣的工作:「觀察表達式,調用回調值改變」。關鍵字差異可能只是語法糖,不會讓開發人員感到困惑。 – 2013-02-14 16:34:33

+1

@fastreload,我完全同意你的評論..寫得很好! – PrimosK 2013-02-14 20:22:14

+0

@fastreload ...感謝您的精彩解釋。如果我理解正確,觀察者是爲了角度表達。我對嗎? – Abilash 2013-02-15 03:17:52

1

我覺得這是很明顯的:

  • $觀察的是在連接指令的功能使用。
  • $ watch用於範圍內觀察其值的任何變化。

記住:兩個函數有兩個參數,

$observe/$watch(value : string, callback : function); 
  • :始終是一個字符串參考看了元素(一個範圍的變量或名稱要注意的指令屬性的名稱)
  • 回調:需要執行的函數function (oldValue, newValue)

我做了一個plunker,所以你可以實際掌握它們的使用情況。我已經使用變色龍比喻來更容易拍照。

+2

它的用法很明顯。但爲什麼是這個問題。馬克把它總結得很漂亮。 – Abilash 2015-05-31 03:49:16

+3

我認爲參數可能被切換 - 它似乎傳遞newValue,然後oldValue傳遞給attrs。$ observe()。 。 。 – blaster 2015-10-14 20:23:29