Vue:销毁时删除事件侦听器

时间:2019-04-13 15:53:27

标签: javascript vue.js

我有一个指示指令,用于将固定的类应用于插入的DOM元素,为此,我还将事件侦听器附加到要在用户滚动时运行的window对象。

我的问题是,我的元素被销毁时是否应该删除此事件侦听器?我听说滚动事件会影响性能,并且我不确定每次刷新页面时事件监听器是否会自动销毁(我的应用程序不是SPA,而是带有vue前端的laravel应用程序)。

这是我的指令:

Vue.directive('scroll-apply-class', {
    isLiteral: true,
    inserted: (el, binding, vnode) => {

        let scrolled = false;
        let stickyTop = 300;

        setTimeout(function(){

            stickyTop = el.offsetTop;

            checkPosition();

            window.addEventListener('scroll', function(e) {
                scrolled = true;
            });

        }, 2500);


        let checkPosition = function(){
            if (window.pageYOffset > stickyTop && window.innerWidth > 765) {
                el.classList.add(binding.value)
            }
            else {
                el.classList.remove(binding.value)
            }   
        };


        let timeout = setInterval(function() {
            if (scrolled) {
                scrolled = false;
                checkPosition();
            }
        }, 2500);

    }
});

2 个答案:

答案 0 :(得分:0)

如果您关心“正派”,那么可以,做对了,删除该侦听器。但是从实用主义者的角度来看,也许不是。由于您的应用程序不是SPA,因此每次用户单击链接并转到其他页面时,都会自动解决该问题。

但还是要视情况而定。在某些情况下,对您的其中一个页面进行一次长期访问时,是否有可能多次加载此指令?如果出现这种情况,则最好取消注册侦听器。如果否,则伪指令仅被加载一次,那么您可以放心地保留它。

答案 1 :(得分:0)

您可以在unbind钩中的窗口上删除事件侦听器。但是,为了删除事件侦听器,您将需要存储它们的回调。这可以通过简单地将其存储为el的属性来完成,例如el.scrollCallback

bind: (el) => {
    el.scrollCallback = () => {
        el.dataset.scrolled = true;
    }
},
unbind: (el) => {
    window.removeEventListener('scroll', el.scrollCallback);
},

然后,在您的inserted钩中,只需更新存储scrolled布尔值的方式即可。您可以将其存储在el的数据集中,而不用将其封装在钩子中,以便其他钩子可以访问它:

inserted: (el, binding, vnode) => {

    // Store data in element directly
    el.dataset.scrolled = false;

    let stickyTop = 300;

    setTimeout(function(){

        stickyTop = el.offsetTop;

        checkPosition();

        window.addEventListener('scroll', el.scrollCallback);

    }, 2500);

    // REST OF YOUR CODE HERE

    // Remember to update all references to `scrolled` to `el.dataset.scrolled`
    let timeout = setInterval(function() {
        if (el.dataset.scrolled) {
            el.dataset.scrolled = false;
            checkPosition();
        }
    }, 2500);

}