双向绑定几乎仅限于使用ng-model
. 从视图到模型的方向使用标准事件处理程序来检测必须在模型中更新的更改(例如,onchange
)。从模型返回视图的方向在$digest
. 但是我们不$digest
直接调用。
页面上将响应摘要循环的每个元素都将在某处使用$watch
. 当您编写{{ foo() }}
或使用 时ng-model='user.name'
,在内部会使用 Javascript 表达式代表您进行调用$watch
,该 Javascript 表达式将在每次运行摘要循环时运行。这种注册可能发生在模板的编译期间(我们的第一个示例),或者它可能发生在指令的链接阶段(我们的第二个示例)。
这里没有魔法。附加的侦听器是常规函数——在我们的示例中,foo()
为您提供了表达式的侦听器,它将更新页面上的 html 文本,而表达式的侦听器user.name
将调用setText
, 或setOption
, 或任何需要的东西通过ng-model
已附加的特定输入。
虽然 Angular 可以处理大部分监听,但您可以在任何可以访问范围的函数中手动将自己的监视表达式与自己的监听器附加在一起(范围很重要,因为如果页面的相应部分被删除,我们将拆除这些监听器)。注意多余。绑定不是免费的,绑定的东西越多,页面响应的速度就越慢。一次性绑定是降低此成本的一种方法。$on
与$emit
和一起使用$broadcast
是另一个。
那么什么时候调用摘要呢?这当然不是自动的。如果摘要循环正在运行,则意味着有人在某个地方调用$apply
了他们的范围或根范围。 ng-model
附加将响应常规 html 事件并$apply
代表您进行调用的处理程序。但是foo()
,另一方面,永远不会被调用,直到某处的其他一些脚本调用$apply
. 幸运的是,您为 angular wrap 填写的大多数函数都使用对 的调用来包装这些函数$apply
,因此您不必经常自己进行调用(例如,$timeout
用 包装$apply
,这就是我们使用它而不是 的原因setTimeout
)。但是,如果您使用的是 angular 范围之外的东西(连接到事件的 3rd 方库),您需要记住调用$apply
您自己,就像上面一样,您可以通过调用$apply
您可以访问范围的任何地方手动执行此操作。