我们有时在自己的vue项目中不可避免的要监听类似scroll事件的,这是如果相对性能影响少点,只能会想到debounce防抖之类的。但是我们要注意了,addEventListener和removeEventListener必须要是同一个函数才行哦,不然removeEventListener是无法移除事件的,这样就容易造成内存泄露了。

平时我们的debounce一般这么用

methods: {
    createDebounce(ms, fn) {
      let prevTime;
      return () => {
        if (prevTime) {
          if (Date.now() - prevTime >= ms) {
            fn();
            prevTime = null;
          }
        } else {
          prevTime = Date.now();
        }
      };
    },
    scrollFn() {
        // ...处理逻辑
    }
}

那我们怎么配合addEventListener和removeEventListener使用呢?
比如

mounted() {
    window.document.addEventListener('scroll', this.createDebounce(800, this.scrollFn);
},
beforeDestroy() {
    window.document.removeEventListener('scroll', this.createDebounce(800, this.scrollFn);
},

首先这样用能起到防抖的作用的,但是removeEventListener是没什么作用的。
因为this.createDebounce执行后会返还一个匿名函数,removeEventListener想要取消的根本不是addEventListener中return的那个。
我们要利用闭包记录prevTime必然createDebounce需要返回一个函数。

怎么解决呢?
我们可以这样

data() {
    return {
        prevTime: null,
    };
},
mounted() {
    window.document.addEventListener('scroll', this.createDebounce(800, this.scrollFn);
},
beforeDestroy() {
    window.document.removeEventListener('scroll', this.createDebounce(800, this.scrollFn);
},
methods: {
    createDebounce(ms, fn) {
        if (this.prevTime) {
          if (Date.now() - this.prevTime >= ms) {
            fn();
            this.prevTime = null;
          }
        } else {
          this.prevTime = Date.now();
        }
    },
    scrollFn() {
        // ...处理逻辑
    }
}

不使用闭包了,直接用this.prevTime,搞定!

没想到好的方案前,这不失为一个解决方案。但是,你是不是觉得这个写法有点low了。

其实我们可以优雅点,这样写的。

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({
          google_ad_client: "ca-pub-3013839362871866",
          enable_page_level_ads: true
     });
</script>
created() {
    this.scroll = this.createDebounce(800, this.scrollFn);
},
mounted() {
    window.document.addEventListener('scroll', this.scroll);
},
beforeDestroy() {
    window.document.removeEventListener('scroll', this.scroll);
},
methods: {
    createDebounce(ms, fn) {
        if (this.prevTime) {
          if (Date.now() - this.prevTime >= ms) {
            fn();
            this.prevTime = null;
          }
        } else {
          this.prevTime = Date.now();
        }
    },
    scrollFn() {
        // ...处理逻辑
    }
}

我们可以直接在created里面在this上面加个方法,而不使用methods里面的方法。

created里面是有this的,可以增加属性或者方法的,并且即使template里面需要用到这个属性或者方法,也是能拿到的,但是要注意响应式的问题,这样直接创建的肯定不是响应式的。

分类: Web前端

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据