如何在指令中安全地清理AngularJS事件绑定

Bil*_*our 24 javascript angularjs

我有一个Angular指令,它将元素的高度设置为等于浏览器窗口的内部高度(+/-给定的偏移量).该指令响应窗口的"resize"事件并相应地调整其高度.当我的指令范围发出'$ destory'事件时,我删除了对"resize"事件的绑定(我认为保留它会导致一些问题,如果我错了就纠正我).

我不知道如何以"安全"的方式做这个事件分离.如果我在我的应用程序中有多个此指令实例,如果我有其他指令附加到'resize'事件怎么办?

JQuery具有事件命名空间的概念,这似乎是一个很好的解决方案,但Angular的实现(JQLite)不支持这一点.因为我已经在使用Angular,所以我宁愿不使用JQuery,所以我该怎么办?

这是我今天指令的代码

window.angular.module('arcFillClient', [])
    .directive('arcFillClientY', ['$window',
        function ($window) {

            function link($scope, el, attrs) {

                var setHeight,
                    onResize,
                    cleanUp;

                setHeight = function (offSetY) {
                    var newHeight;
                    offSetY = offSetY || 0;
                    newHeight = Math.max($window.innerHeight + parseInt(offSetY, 10)) + 'px';
                    el.height(newHeight);
                };

                onResize = function () {
                    var offset;
                    offset = attrs.arcFillClientY || 0;
                    setHeight(offset);
                };

                attrs.$observe('arcFillClientY', setHeight);
                window.angular.element($window).on('resize', onResize);

                cleanUp = function () {
                    window.angular.element($window).off('resize');
                };

                $scope.$on('$destroy', cleanUp);
            }
            return {
                link: link
            };
Run Code Online (Sandbox Code Playgroud)

更新看起来像RTFM的情况,但万一其他人徘徊在这里,这里有一些更多的信息.将原始函数(在我的情况下OnResize)传递给.off()工程以隔离.off()函数的范围.来自文档:

还可以通过在handler参数中指定函数名来删除处理程序.当jQuery {ahem ... JQLite}附加一个事件处理程序时,它会为处理函数分配一个唯一的id.

这是cleanUp我的指令中更新的函数:

cleanUp = function () {
    window.angular.element($window).off('resize', onResize);
};
Run Code Online (Sandbox Code Playgroud)

感谢tasseKATT,Karolis和Hans的贡献.

tas*_*ATT 29

通过同样的功能引用off,你传递给on:

window.angular.element($window).off('resize', onResize);
Run Code Online (Sandbox Code Playgroud)

代替:

window.angular.element($window).off('resize');
Run Code Online (Sandbox Code Playgroud)

演示 - 将函数引用传递给off:http://plnkr.co/edit/1rfVPNXl6TrEcuYvzPAj?p = preview

演示 - 不将函数引用传递给off:http://plnkr.co/edit/IsLqSLAzNcHqDnhMty7Q?p = preview

演示包含两个指令,都监听窗口调整大小事件.使用代码和预览之间的垂直分隔符来触发事件.

您会注意到,如果您销毁一个,则另一个将在将函数引用传递给off时继续工作.如果不这样做,两者都会停止工作.


Han*_*ans 5

几个星期前,我有同样的问题.

在查看了jqLit​​e源代码(https://github.com/angular/angular.js/blob/master/src/jqLit​​e.js)后,我们看到该on方法添加了该事件,该off方法通过该jqLiteOff函数删除了该事件.

看得更深,我们看到了jqLiteRemoveData电话jqLiteOff.jqLiteRemoveData被称为jqLiteDealoc.jqLiteDealoc被调用在几个地方:jqLiteEmpty,html,replaceWith,和remove.jqLiteEmpty被赋值给元素的empty方法,它清除了jQuery中的元素.html,replaceWith并且remove是jQuery的模仿.

remove()在对元素调用的位置进行搜索时,我们看到它在大多数(如果不是全部)DOM操作逻辑上使用.你可以看到它ngIf,ngSwitch,ngIncludengView.

所以我认为Angular会处理事件监听器清理,只要你使用jqLit​​e附加事件并remove()在你自己的DOM操作逻辑中适当调用.使用jQuery包装元素会搞砸很多进程,包括事件监听器清理,但我猜你已经完全清楚了,因为你正在使用它angular.element.