【问题标题】:one-time binding to custom attribute directive一次性绑定到自定义属性指令
【发布时间】:2016-04-04 09:05:27
【问题描述】:

我正在为基于特定属性的自定义指令使用角度一次性绑定 (relative)

这是我的指令:

app.directive('relative', ['$timeout', '$filter', '$compile', function ($timeout, $filter, $compile) {
    var dateFilter = $filter('date');

    return {
        restrict: 'A',
        scope: {
            datetime: '@'
        },
        link: function ($scope, $element, $attributes) {
            var timeout;

            $scope.$watch('datetime', function (dateString) {
                $timeout.cancel(timeout);

                var date = (dateString || $element.text()) * 1000;
                if (!date) return;
                date = new Date(date);
                if (!date) return;

                function update() {
                    var reference = new Date();
                    $element.text(prettyDate(date));

                    //Calculate the next update
                    var diff = Math.abs(date - reference) / 1000;
                    var delta;
                    if (diff < 45) {
                        delta = 45 - diff;
                    } else if (diff < 90) {
                        delta = 90 - diff;
                    } else if (diff < 45 * 60) {
                        delta = 60 - (diff + 30e3) % 60;
                    } else {
                        delta = 3660 - diff % 3600;
                    }

                    timeout = $timeout(update, delta * 1000);
                }

                update();    

                $element.on('$destroy', function () {
                    $timeout.cancel(timeout);
                });
            });
        }
    };
}]);

这就是我使用它的方式:

 <time relative datetime="{{ notice.date }}"></time>

或者:

 <time relative datetime="{{ ::notice.date }}"></time>

问题是:当使用一次性绑定时,如何避免为 datetime 属性创建监视,因为该值永远不会改变? Angular 会自动完成吗?

【问题讨论】:

  • 你自己创建一个watcher,绑定值后可以自己移除,以防一次性绑定。如果你有自己的观察者,datetime: '@' 毫无意义。

标签: angularjs angularjs-directive binding


【解决方案1】:

我相信您最初是使用$watch 来触发update 函数。您应该避免使用观察者,并选择在观察者之外重构初始化。为了避免 Angular 将监视变量添加到监视列表时的初始触发,您可以这样做 (source):

$scope.$watch('datetime', function (dateString, oldDateString) {
    // notice the use of strict equality operator '==='
    // angular ensures this will only be true on the initialization of the watcher
    if (dateString === oldDateString) {
        return;
    }
});

使用&lt;time relative datetime="{{ ::notice.date }}"&gt;&lt;/time&gt; angular 不会在一次性绑定后触发观察者。

在检查了Scope 对象上的$$watchers 属性后,我看不出有或没有$watch 注册的观察者数量有什么区别,我怀疑batarang 正在使用它。

针对您的问题,我认为无法避免创建具有一次性绑定的观察者。

【讨论】:

  • 但是像 angular batarang 这样的工具显示有一个手表处于活动状态,即使由于一次性绑定而没有触发。
  • 一旦你声明了一个观察者,Angular 就会将它添加到观察者中。解决这个问题的一个笨方法是添加另一个属性并检查它是否存在,然后添加观察者。
  • @JavierMarín 在检查了我看到的内容之后,您可能会因为从父级绑定到子级范围而获得观察者,即scope: { datetime: '@' },所以batarang 可能会向您展示您不期望的东西。我将编辑我的回复说你不能停止观察者的初始化。
  • 我最终添加了另一个属性,当它存在时,我不调用 $watch
【解决方案2】:

我认为this 是您正在寻找的解决方案。

您可以通过属性获取日期时间值,而不是通过范围对象接受它。这将避免创建不需要的手表。无论如何,您不希望该值会发生变化,因此它实际上不会产生太大影响。

【讨论】:

  • 但我并不总是对该属性使用一次性绑定,我只是展示了该值不变时的特殊情况。我编辑了问题以澄清这一点。
猜你喜欢
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 2012-12-07
  • 1970-01-01
  • 2012-08-29
  • 1970-01-01
  • 1970-01-01
  • 2011-05-11
相关资源
最近更新 更多