我最初的理解是观察者计算角度表达式是HTML侧的条件,当Watcher执行$ scope。$ watch()函数执行时。我是否正确思考?
例如,attr1 =“Name:{{name}}”,然后在一个伪指令中:attrs。$ observe(‘attr1’,…)。
(如果你尝试范围$ watch(attrs.attr1,…)它将无法工作,因为{{}} – 你会得到undefined。)使用$ watch的一切。
$watch()更复杂。它可以观察/观察一个“表达式”,其中表达式可以是一个函数或一个字符串。如果表达式是一个字符串,它是$parse(即,评估为Angular expression)到一个函数。 (这个函数被称为每个摘要周期。)字符串表达式不能包含{{}}。 $ watch是一个对Scope对象的方法,所以它可以使用/调用,无论你有权访问范围对象,因此在
>控制器 – 任何控制器 – 通过ng-view,ng-controller或指令控制器创建的控制器
>指令中的链接函数,因为它也可以访问作用域
因为字符串被评估为角度表达式,所以当你想观察/观察模型/范围属性时,通常使用$ watch。例如,attr1 =“myModel.some_prop”,然后在控制器或链接函数:scope。$ watch(‘myModel.some_prop’,…)或范围$ watch(attrs.attr1,…) 。$ watch(attrs [‘attr1’],…))。
(如果你尝试attrs。$ observe(‘attr1’),你会得到字符串myModel.some_prop,这可能不是你想要的。
正如在对PrimosK的回答的评论中所讨论的,所有$观察和$手表每digest cycle检查。
与隔离范围的指令更复杂。如果使用’@’语法,您可以$ observe或$观看包含插值的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和$ watches是由点击处理程序所做的属性更改触发的。
请注意,当链接函数运行时,包含{{}}的任何属性都不会被求值(因此,如果您尝试检查属性,则会得到undefined)。看到内插值的唯一方法是使用$ observe(或$ watch如果使用带有’@’的隔离范围)。因此,获取这些属性的值是一个异步操作。 (这就是为什么我们需要$ observe和$ watch函数。)
有时你不需要$ observe或$ watch。例如,如果您的属性包含数字或布尔值(不是字符串),只需计算一次:attr1 =“22”,然后在例如您的链接函数:var count = scope。$ eval(attrs.attr1)。如果它只是一个常量字符串 – attr1 =“my string” – 那么只需在你的指令中使用attrs.attr1(不需要$ eval())。
另请参见Vojta’s google group post关于$ watch表达式。