angularjs 中的脏数据检查-ag捕鱼王app官网

angularjs 中的脏数据检查

作者:迹忆客 最近更新:2023/03/14 浏览次数:

我们将介绍如何在 angularjs 中进行脏数据检查。

在 angularjs 中实现脏数据检查

angularjs 对双向数据绑定的 $scope 变量执行脏数据检查。ember.js 通过以编程方式修复 setter 和 getter 来执行双向数据绑定,但在 angular 中,脏数据检查允许它查找可能可用或不可用的变量。

# angularjs
$scope.$watch( wexp, listener, objeq );

$scope.$watch 函数用于我们想要查看变量何时被更改。我们必须选择三个参数来应用这个函数:wexp 是我们想要观看的内容,listener 是我们希望它在更新时执行的操作,以及我们想要检查变量还是对象。

当我们想要检查一个变量时,我们可以在使用这个函数时跳过这个。让我们看一个例子,如下所示。

#angularjs
$scope.newname = 'subhan';
$scope.$watch( function( ) {
    return $scope.name;
}, function( newval, oldval ) {
    console.log('$scope.newname is updated!');
} );

angular 会将你的 watcher 函数保存在 $scope 中。你可以通过将 $scope 记录到控制台来检查这一点。

$watch 中,我们还可以使用字符串代替函数。这也将与函数的工作方式相同。

当我们在 angular 源代码中添加一个字符串时,代码将是:

#angularjs
if (typeof wexp == 'string' && get.constant) {
  var newfn = watcher.fn;
  watcher.fn = function(newval, oldval, scope) {
    newfn.call(this, newval, oldval, scope);
    arrayremove(array, watcher);
  };
}

通过应用此代码,wexp 将被设置为一个函数。这将使用具有我们选择的名称的变量指定我们的侦听器。

angularjs 中的 $watchers 函数

所有选定的观察者都将存储在 $scope 中的 $$watchers 变量中。当我们检查 $$watchers 时,你会发现一个对象数组,如下所示。

#angularjs
$$watchers = [
    {
        eq: false,
        fn: function( newval, oldval ) {},
        last: 'subhan',
        exp: function(){},
        get: function(){}
    }
];

unregwatch 函数由 $watch 函数返回。这表明如果我们想将初始的 $scope.$watch 分配给一个变量,我们可以通过命令它停止观察来轻松实现这一点。

只需确认我们已经打开并查看了在断开观察程序之前记录的第一个 $scope

angularjs 中的 $scope.$apply 函数

当我们尝试运行 controller/directive/etc. 时,angular 会运行一个函数,我们在其中调用 $scope.$watch。在管理 rootscope 中的 $digest 函数之前,$apply 函数将运行我们选择的函数。

angular $apply 函数如下:

#angularjs
$apply: function(expr) {
    try {
      beginphase('$apply');
      return this.$eval(expr);
    } catch (e) {
      $exceptionhandler(e);
    } finally {
      clearphase();
      try {
        $rootscope.$digest();
      } catch (e) {
        $exceptionhandler(e);
        throw e;
      }
    }
}

angularjs 中的 expr 参数

当使用 $scope.$apply 时,有时 angular 或者我们会通过一个函数,expr 参数就是那个函数。

在使用此功能时,我们不会发现需要最频繁地使用 $apply。让我们看看当 ng-keydown 使用 $scope.$apply 时会发生什么。

要提交指令,我们使用以下代码。

#angularjs
var eventngdirective = {};
foreach(
  keydown keyup keypress submit focus blur copy cut paste'.split(' '),
  function(newname) {
    var newdirectivename = newdirectivenormalize('ng-'   newname);
    eventngdirective[newdirectivename] = ['$parse', function($parse) {
      return {
        compile: function($element, attr) {
          var fn = $parse(attr[directivename]);
          return function ngeventhandler(scope, element) {
            element.on(lowercase(newname), function(event) {
              scope.$apply(function() {
                fn(scope, {$event:event});
              });
            });
          };
        }
      };
    }];
  }
);

此代码将遍历可以触发的不同类型的事件,生成一个名为 ng(eventname) 的新指令。当涉及指令的编译功能时,事件处理程序被记录在元素上,其中事件包含指令的名称。

当这个事件被触发时,angular 将运行 $scope.$apply,为其提供一个运行函数。

这就是 $scope 值将如何使用元素值更新的方式,但此绑定只是单向绑定。这样做的原因是我们应用了 ng-keydown,它允许我们仅在应用此事件时进行更改。

结果,得到了一个新的值!

我们的主要目标是实现双向数据绑定。为了实现这个目标,我们可以使用 ng-model

为了使 ng-model 发挥作用,它同时使用 $scope.$watch$scope.$apply

我们给出的输入将通过 ng-model 加入事件处理程序。此时,调用了 $scope.$watch

$scope.$watch 在指令的控制器中被调用。

#angularjs
$scope.$watch(function ngmodelwatch() {
    var value = ngmodelget($scope);
    if (ctrl.$modelvalue !== value) {
        var formatters = ctrl.$formatters,
            idx = formatters.length;
        ctrl.$modelvalue = value;
        while(idx--) {
            value = formatters[idx](value);
        }
        if (ctrl.$viewvalue !== value) {
            ctrl.$viewvalue = value;
            ctrl.$render();
        }
    }
    return value;
});

当设置 $scope.$watch 时仅使用一个参数时,我们选择的函数将被应用,即使它是否已更新。ng-model 中的函数检查模型和视图是否同步。

如果不同步,该函数会给模型一个新值并更新它。当我们在 $digest 中运行这个函数时,这个函数允许我们通过返回新值来知道新值是什么。

为什么监听器没有被触发

让我们回到示例中的点,我们在与我们描述的类似的函数中取消注册了 $scope.$watch 函数。我们现在可以承认没有收到有关更新 $scope.name 的通知的原因,即使我们已经更新了它。

正如我们所知,$scope.$apply 由 angular 在每个指令控制器函数上运行。当我们估计了指令的控制器功能时,$scope.$apply 函数将仅在一个条件下运行 $digest

这意味着我们在 $scope.$watch 函数能够执行之前取消了它的注册,因此它被调用的可能性很小甚至没有。

angularjs 中的 $digest 函数

你可以通过 $scope.$apply$rootscope 上调用此函数。我们可以在 $rootscope 上运行摘要循环,然后它将越过范围并运行摘要循环。

摘要循环将触发我们在 $$watchers 变量中的所有 wexp 函数。它将根据最后一个已知值检查它们。

如果结果是否定的,监听器将被触发。

在摘要循环中,当它运行时,它会循环两次。一次,它将在观察者之间循环,然后再次循环,直到循环不再是

wexp 和最后一个已知值不相等时,我们说循环是脏的。通常这个循环会运行一次,如果运行十次以上就会报错。

angular 可以在任何可能改变模型值的东西上运行 $scope.$apply

你必须运行 $scope.$apply(); 当我们在 angular 之外更新了 $scope。这将通知 angular 范围已更新。

让我们设计一个基本版本的脏数据检查。

我们希望保存的所有数据都将在 scope 函数中。我们将在函数上扩展对象以复制 $digest$watch

因为我们不需要评估与 scope 有关的函数,所以我们不会使用 $apply。我们将直接使用 $digest

这就是我们的 scope 的样子:

#angularjs
var scope = function( ) {
    this.$$watchers = [];
};
scope.prototype.$watch = function( ) {
};
scope.prototype.$digest = function( ) {
};

$watch 应该采用两个参数,wexplistener。我们可以在 scope 中设置值。

$watch 被调用时,我们将它们发送到先前存储在 scope 中的 $$watcher 值中。

#angularjs
var scope = function( ) {
    this.$$watchers = [];
};
scope.prototype.$watch = function( wexp, listener ) {
    this.$$watchers.push( {
        wexp: wexp,
        listener: listener || function() {}
    } );
};
scope.prototype.$digest = function( ) {
};

在这里,我们会注意到 listener 设置为一个空函数。

当没有提供 listener 时,你可以按照此示例轻松为所有变量注册 $watch

现在我们将运行 $digest。我们可以检查旧值和新值是否相等。

如果监听器尚未被触发,我们也可以触发它。为此,我们将循环直到它们相等。

dirtychecking 变量帮助我们实现了这个目标,无论值是否相等。

#angularjs
var scope = function( ) {
    this.$$watchers = [];
};
scope.prototype.$watch = function( wexp, listener ) {
    this.$$watchers.push( {
        wexp: wexp,
        listener: listener || function() {}
    } );
};
scope.prototype.$digest = function( ) {
    var dirtychecking;
    do {
            dirtychecking = false;
            for( var i = 0; i < this.$$watchers.length; i   ) {
                var newval = this.$$watchers[i].wexp(),
                    oldval = this.$$watchers[i].last;
                if( oldval !== newval ) {
                    this.$$watchers[i].listener(newval, oldval);
                    dirtychecking = true;
                    this.$$watchers[i].last = newval;
                }
            }
    } while(dirtychecking);
};

现在,我们将设计一个新的范围示例。我们将把它分配给 $scope;然后,我们将注册一个 watch 函数。

然后我们将更新它并消化它。

#angularjs
var scope = function( ) {
    this.$$watchers = [];
};
scope.prototype.$watch = function( wexp, listener ) {
    this.$$watchers.push( {
        wexp: wexp,
        listener: listener || function() {}
    } );
};
scope.prototype.$digest = function( ) {
    var dirtychecking;
    do {
            dirtychecking = false;
            for( var i = 0; i < this.$$watchers.length; i   ) {
                var newval = this.$$watchers[i].wexp(),
                    oldval = this.$$watchers[i].last;
                if( oldval !== newval ) {
                    this.$$watchers[i].listener(newval, oldval);
                    dirtychecking = true;
                    this.$$watchers[i].last = newval;
                }
            }
    } while(dirtychecking);
};
var $scope = new scope();
$scope.newname = 'subhan';
$scope.$watch(function(){
    return $scope.newname;
}, function( newval, oldval ) {
    console.log(newval, oldval);
} );
$scope.$digest();

我们已经成功实现了脏数据检查。当我们观看控制台时,你将观察其日志。

#angularjs
subhan undefined

以前,未定义 $scope.newname。我们已经为 subhan 修复了它。

我们将把 $digest 函数连接到输入上的 keyup 事件。通过这样做,我们不必自己指定它。

这意味着我们也可以实现双向数据绑定。

#angularjs
var scope = function( ) {
    this.$$watchers = [];
};
scope.prototype.$watch = function( wexp, listener ) {
    this.$$watchers.push( {
        wexp: wexp,
        listener: listener || function() {}
    } );
};
scope.prototype.$digest = function( ) {
    var dirty;
    do {
            dirtychecking = false;
            for( var i = 0; i < this.$$watchers.length; i   ) {
                var newval = this.$$watchers[i].wexp(),
                    oldval = this.$$watchers[i].last;
                if( oldval !== newval ) {
                    this.$$watchers[i].listener(newval, oldval);
                    dirtychecking = true;
                    this.$$watchers[i].last = newval;
                }
            }
    } while(dirtychecking);
};
var $scope = new scope();
$scope.newname = 'subhan';
var element = document.queryselectorall('input');
element[0].onkeyup = function() {
    $scope.newname = element[0].value;
    $scope.$digest();
};
$scope.$watch(function(){
    return $scope.newname;
}, function( newval, oldval ) {
    console.log('value updated in input - the new value is '   newval);
    element[0].value = $scope.newname;
} );
var updatescopevalue = function updatescopevalue( ) {
    $scope.name = 'butt';
    $scope.$digest();
};

使用这种技术,我们可以轻松地更新输入的值,如 $scope.newname 中所示。你也可以调用 updatescopevalue,输入的值会显示出来。

上一篇:angular 中带有多个条件的 ng-if

下一篇:

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便
网站地图