如何在AngularJS中使用$scope.$watch和$scope.$apply?

34 浏览
0 Comments

如何在AngularJS中使用$scope.$watch和$scope.$apply?

我不明白如何使用$scope.$watch和$scope.$apply。官方文档并没有帮助我。\n具体我不理解的是:\n- 它们是否与DOM有关?\n- 如何将DOM更改更新到模型中?\n- 它们之间的连接点是什么?\n\n我尝试了这篇教程,但它默认你已经理解了$scope.$watch和$scope.$apply。\n$scope.$apply和$scope.$watch是用来做什么的?我应该如何恰当地使用它们?

0
0 Comments

在AngularJS中,我们更新我们的模型,然后我们的视图/模板“自动”(通过内置或自定义指令)更新DOM。\n$apply和$watch是Scope方法,与DOM无关。\n“概念”页(部分“运行时”)有一个$digest循环,$apply,$evalAsync队列和$watch列表的相当好的解释。这是伴随文本的图片:\n任何访问作用域的代码 - 通常是控制器和指令(它们的链接函数和/或它们的控制器) - 都可以设置一个“watchExpression”,AngularJS将对该作用域进行评估。此评估发生每当AngularJS进入其$digest循环时(特别是“$watch list”循环)。您可以监视个别作用域属性,可以定义一个函数来一起监视两个属性,可以监视数组的长度等。\n当事情发生“在AngularJS内部”时 - 例如,您键入启用了AngularJS双向数据绑定(即使用ng-model)的文本框,$http回调被触发等 - $apply已经被调用,因此我们位于上图中的“AngularJS”矩形中。所有watchExpression将被评估(可能不止一次 - 直到不再检测到更改)。\n当事情发生“在AngularJS外部”时 - 例如,您在指令中使用了绑定()然后事件发生,导致调用您的回调,或某个jQuery注册的回调被触发 - 我们仍在“本机”矩形中。如果回调代码修改任何$watch正在观察的内容,请调用$apply以进入AngularJS矩形,从而使$digest循环运行,因此AngularJS将注意到更改并执行其魔法。

0
0 Comments

你需要了解AngularJS的工作原理才能理解它。

循环与$scope

首先,AngularJS定义了一个所谓的循环(digest cycle)的概念。这个循环可以被看作是一个循环,在这个循环中AngularJS检查所有被所有$scope所监视的变量是否有任何变化。因此,如果你在控制器中定义了$scope.myVar,并且这个变量被标记为被监视,那么你正在暗示AngularJS在每次循环迭代中监视myVar的变化。

一个自然的后续问题是:所有附加到$scope上的东西都会被监视吗?幸运的是,不会。如果您要监视$scope中的每个对象的变化,那么循环将需要花费大量时间进行评估,您将很快遇到性能问题。这就是为什么AngularJS团队给了我们两种方法来声明一些$scope变量作为被监视的方式(见下文)。

$watch帮助监听$scope的变化

有两种方法可以声明$scope变量作为被监视的方式。

  1. 通过在表达式{{myVar}}中在您的模板中使用它
  2. 通过手动添加$watch服务

广告1)
这是最常见的情况,我相信你以前见过它,但你不知道这已经在后台创建了一个监视器。是的,它有!使用AngularJS指令(例如ng-repeat)也可以创建隐式监视器。

广告 2)
以下是如何创建自己的 手表$watch 服务可在附加到 $scope 的值发生更改时运行一些代码。虽然很少使用,但有时很有用。例如,如果要在每次“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 使更改与循环中的摘要集成

您可以将$apply 函数视为集成机制。您看,每次直接更改附加到 $scope观察变量时,AngularJS 都会知道已发生更改。这是因为 AngularJS 已知要监视这些更改。因此,如果它发生在由框架管理的代码中,则摘要循环将继续。

但是,有时您想要在 AngularJS 外更改某些值,并且希望看到更改正常传播。
假设您有一个 $scope.myVar 值,它将在 jQuery 的 $.ajax() 处理程序内修改。这将发生在未来的某个时刻。AngularJS 不能等待此操作完成,因为尚未指示它等待 jQuery。

为了应对这种情况,引入了 $apply。它允许您显式启动摘要循环。但是,您只应将此方法用于将某些数据迁移到 AngularJS(与其他框架的集成),但不能将此方法与常规 AngularJS 代码组合使用,因为那样 AngularJS 将报错。

所有这些与 DOM 有什么关系?

嗯,既然您已经了解了这些,那么您应该重新关注一下教程。摘要循环将确保 UI 和 JavaScript 代码保持同步,通过评估附加到所有 $scope 的 watcher,只要没有更改发生。如果在摘要循环中不再发生更改,则视为已完成。

你可以通过在控制器中显式地添加对象或直接在视图中以{{expression}}的形式声明的方式将对象附加到$scope对象上。

进一步阅读:

0