Answers:
您需要了解AngularJS的工作原理才能理解它。
首先,AngularJS定义了所谓的摘要循环的概念。此循环可以视为一个循环,在此循环中AngularJS检查所有s 监视的所有变量是否有任何更改$scope
。因此,如果您已$scope.myVar
在控制器中定义并且该变量被标记为“正在监视”,那么您将隐式告诉AngularJS监视myVar
循环的每次迭代中的更改。
一个自然而然的跟进问题是:是否一切都与$scope
被监视有关?幸运的是,没有。如果您要监视中的每个对象的更改$scope
,那么摘要循环很快就会花费很多时间进行评估,并且您会很快遇到性能问题。这就是AngularJS团队为我们提供了两种方法来声明某些$scope
变量被监视的原因(请参阅下文)。
有两种方法将$scope
变量声明为被监视。
<span>{{myVar}}</span>
$watch
服务手动添加广告1)这是最常见的情况,我敢肯定您以前看过它,但是您不知道这是在后台创建手表的。是的,它有!使用AngularJS指令(例如ng-repeat
)也可以创建隐式监视。
广告2)这就是您制作手表的方式。$watch
当附加到的值$scope
更改时,service服务可以帮助您运行一些代码。它很少使用,但有时会有所帮助。例如,如果您希望每次“ myVar”更改时都运行一些代码,则可以执行以下操作:
function MyController($scope) {
$scope.myVar = 1;
$scope.$watch('myVar', function() {
alert('hey, myVar has changed!');
});
$scope.buttonClicked = function() {
$scope.myVar = 2; // This will trigger $watch expression to kick in
};
}
您可以将$apply
功能视为集成机制。您会看到,每次更改直接附加到$scope
对象的某些监视变量时,AngularJS都会知道更改已发生。这是因为AngularJS已经知道监视这些更改。因此,如果发生在框架管理的代码中,则摘要循环将继续进行。
但是,有时您想在AngularJS世界之外更改一些值,并看到更改可以正常传播。考虑一下-您有一个$scope.myVar
将在jQuery $.ajax()
处理程序中修改的值。这将在将来的某个时刻发生。AngularJS不能等待这种情况发生,因为尚未指示它等待jQuery。
为了解决这个问题,$apply
已经引入。它使您可以显式启动消化周期。但是,您仅应使用此方法将某些数据迁移到AngularJS(与其他框架集成),而决不要将此方法与常规AngularJS代码结合使用,因为AngularJS会抛出错误。
好了,既然您已经知道了所有这些,那么您应该再次真正遵循该教程。$scope
只要没有任何变化,摘要周期就可以通过评估附加到所有的每个观察程序来确保UI和JavaScript代码保持同步。如果摘要循环中没有更多更改发生,则视为已完成。
您可以$scope
在Controller中显式地将对象附加到对象,也可以{{expression}}
直接在视图中以形式声明它们。
我希望这有助于澄清有关这一切的一些基本知识。
进一步阅读:
在AngularJS中,我们更新模型,并且视图/模板“自动”(通过内置或自定义指令)更新DOM。
$ apply和$ watch都是Scope方法,与DOM不相关。
该概念页(参考“运行”)具有消化$循环的一个很好的解释,$应用中,$ evalAsync队列和$观察名单。这是文本随附的图片:
无论什么代码可以访问范围(通常是控制器和指令(它们的链接函数和/或其控制器)),都可以设置“ watchExpression ”,AngularJS将在该范围内对其进行评估。每当AngularJS进入其$ digest循环(尤其是“ $ watch list”循环)时,都会进行此评估。您可以观察单个作用域属性,可以定义一个函数来一起观察两个属性,可以观察数组的长度,等等。
当事情发生在“ AngularJS内部”时–例如,您键入一个启用了AngularJS双向数据绑定的文本框(即,使用ng-model),触发$ http回调等。–已经调用$ apply,因此我们在上图中的“ AngularJS”矩形内。将对所有watchExpressions进行评估(可能不止一次-直到未检测到进一步的更改为止)。
当事情发生在“ AngularJS外部”时(例如,您在指令中使用bind(),然后触发该事件,导致您的回调被调用,或者某些jQuery注册的回调被触发),我们仍然位于“本机”矩形中。如果回调代码修改了任何$ watch正在监视的内容,请调用$ apply以进入AngularJS矩形,从而导致$ digest循环运行,因此AngularJS将注意到这一变化并发挥其魔力。
scope.$apply(scope.model)
,我不知道要传输什么数据以及如何将其传输到模型中的正确位置?
scope.$apply(scope.model)
将简单地scope.model
作为Angular表达式求值,然后进入$ digest循环。在您引用的文章中,可能scope.$apply()
已经足够了,因为该模型已经被监视了。stop()函数正在更新模型(我相信toUpdate是对scope.model的引用),然后调用$ apply。
AngularJS扩展了这个事件循环,创建了一个叫做AngularJS context
。
$ watch()
每次在UI中绑定内容时,都会$watch
在$watch
列表中插入一个。
User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />
在这里,我们有$scope.user
,它绑定到第一个输入,而我们有$scope.pass
,它绑定到第二个输入。这样做,我们将两个es添加$watch
到$watch
列表中。
加载我们的模板(即链接阶段)时,在链接阶段,编译器将查找每个指令并创建$watch
所需的所有es。
AngularJS提供$watch
,$watchcollection
和$watch(true)
。下面是一张简洁的图表,深入地解释了从观察者身上提取的所有三种情况。
angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
$scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];
$scope.$watch("users", function() {
console.log("**** reference checkers $watch ****")
});
$scope.$watchCollection("users", function() {
console.log("**** Collection checkers $watchCollection ****")
});
$scope.$watch("users", function() {
console.log("**** equality checkers with $watch(true) ****")
}, true);
$timeout(function(){
console.log("Triggers All ")
$scope.users = [];
$scope.$digest();
console.log("Triggers $watchCollection and $watch(true)")
$scope.users.push({ name: 'Thalaivar'});
$scope.$digest();
console.log("Triggers $watch(true)")
$scope.users[0].name = 'Superstar';
$scope.$digest();
});
}
$digest
环当浏览器收到可以由AngularJS上下文管理的事件时,$digest
将触发循环。此循环由两个较小的循环组成。一个处理$evalAsync
队列,另一个处理队列$watch list
。在$digest
通过的名单将循环$watch
,我们有
app.controller('MainCtrl', function() {
$scope.name = "vinoth";
$scope.changeFoo = function() {
$scope.name = "Thalaivar";
}
});
{{ name }}
<button ng-click="changeFoo()">Change the name</button>
这里只有一个,$watch
因为ng-click不会创建任何手表。
我们按下按钮。
$digest
循环将运行,并将要求每个$ watch进行更改。$watch
正在监视$ scope.name的更改报告了更改,因此它将强制执行另一个$digest
循环。$digest
循环。这意味着,每当我们在输入中写一个字母时,循环将运行检查$watch
此页面中的每个字母。如果$apply
在事件触发时调用,它将经过角度上下文,但是如果不调用,它将在事件外部运行。就是这么简单。$apply
将呼叫$digest()
内部循环,并将迭代所有监视,以确保使用新更新的值来更新DOM。
该$apply()
方法将触发整个$scope
链上的监视程序,而该$digest()
方法将仅触发当前$scope
及其链表上的监视程序children
。当没有任何上层$scope
对象需要了解本地更改时,可以使用$digest()
。
我发现了非常深入的视频覆盖$watch
,$apply
,$digest
并在消化周期:
以下是这些视频中使用的几张幻灯片来解释这些概念(以防万一,如果上述链接被删除/不起作用)。
在上图中,由于未在任何数据绑定(在标记中)使用“ $ scope.c”,因此未对其进行监视。其他两个($scope.a
和$scope.b
)将被监视。
从上图可以看出:AngularJS基于各自的浏览器事件,捕获事件,执行摘要循环(遍历所有监视更改),执行监视功能并更新DOM。如果不是浏览器事件,则可以使用$apply
或手动触发摘要周期$digest
。
有关$apply
和的更多信息$digest
:
也有$watchGroup
和$watchCollection
。特别$watchGroup
是,如果您要调用一个函数来更新不是dom对象的视图中具有多个属性的对象(例如,画布,WebGL或服务器请求中的另一个视图),则确实有帮助。
在这里,文档链接。
刚读完以上所有内容,无聊又困(很抱歉,是真的)。非常技术性,深入,详细和干燥。我为什么写作?由于AngularJS庞大,因此许多相互关联的概念会让任何人发疯。我经常问自己,我不够聪明,无法理解它们吗?没有!这是因为很少有人能够用傻瓜语言来解释技术所有术语!好吧,让我尝试:
1)它们都是事件驱动的东西。(我听到笑声,但继续读)
如果您不知道事件驱动的是什么,那就以为您在页面上放置了一个按钮,并使用“ on-click”将其与一个函数挂钩,等待用户单击它来触发您在页面内部植入的动作。功能。或想到SQL Server / Oracle的“触发器”。
2)$ watch是“点击”的。
特殊之处在于它使用2个函数作为参数,第一个函数从事件中给出值,第二个函数将值考虑在内...
3)$ digest是不知疲倦地四处检查的老板,但又是一个好老板。
4)$ apply为您提供了一种手动进行操作的方式,例如一种防故障功能(如果单击不起作用,则可以强制其运行。)
现在,让我们将其可视化。想象一下,使它更容易掌握:
在一家餐馆,
- 服务员
应该接受客户的订单,这是
$watch(
function(){return orders;},
function(){Kitchen make it;}
);
-经理到处跑来确保所有服务员都醒着,以响应客户的任何变化迹象。这是$digest()
-OWNER有权根据要求驱动所有人$apply()