在 2020 年,我需要在第二次初始化时调用 "removeEventListener" 吗?

In 2020 do i need to call "removeEventListener" on 2nd initialization?

我有连续动画,用 gsap library 制作。我正在使用 mouseover/mouseout 事件来 pause/resume 这个动画。在 window 调整大小事件中,我正在重新初始化。我的问题是:我需要在第二次初始化时调用 removeEventListener 吗?

这里是 code/scenario:

const scroll = {

    create: function (el) {

        this.scrollAnimation = gsap.timeline({
            repeat: -1
        });

        // another piece of awesome code here...

        this.create__addMouseEvents(el);
    },
    create__addMouseEvents: function (el) {

        // here, on window resize event( when i call update(), during re-initialization ), do i need to call "removeEventListener"?

        el.addEventListener('mouseover', () => this.scrollAnimation.pause());

        el.addEventListener('mouseout', () => this.scrollAnimation.resume());

    },

    update: function () {
        // 
        // destroy old "scrollAnimation" if it's already exists
        if (this.scrollAnimation) {
            this.scrollAnimation.kill();
        }
        // 
        // reinit
        this.init();
    },

    init: function () {
        
        // some awesome code here...

        this.create(el);
    }
}


document.addEventListener('DOMContentLoaded', function () {
    
    scroll.init();

});


let windowResizeTimer;
window.addEventListener('resize', function () {
    
    clearTimeout(windowResizeTimer);
    
    windowResizeTimer = setTimeout(function () {
        
        scroll.update();

    }, 150);

});

您目前每次更新都会向浏览器添加一个新事件。一个简单的解决方案如下:

const scroll = {
  eventsAlreadyAdded: false,
  create: function (el) {
    this.scrollAnimation = gsap.timeline({ repeat: -1 });
    // another piece of awesome code here...

    if (!scroll.eventsAlreadyAdded) {
      this.create__addMouseEvents(el);
      scroll.eventsAlreadyAdded = true;
    }
  },
  create__addMouseEvents: function (el) { /* .. */ },
  update: function () { /* .. */ },
  init: function () { /* .. */ }
}

由于您没有实例化滚动对象,因此必须更改全局引用scroll.eventsAlreadyAdded。

或者,您可以稍微重写代码,以便处理实例化变量(未测试):


class Scroll {
  /**
   * Returns the element
   * @type {Node}
   */
  static get element() {
    return document.querySelector('THE ELEMET SELECTOR');
  }

  /**
   * Initial the scroll event to given element
   * @param {Node} el the element that will get an animation
   */
  constructor(el) {
    this.el = el;

    /**
     * Remembers whether the events have already been attached to the element
     * @type {boolean}
     */
    this.eventsAlreadyAdded = false;

    /**
     * The timeline instanze from gsap
     * @type {Timeline}
     */
    this.scrollAnimation = null;

    this.create();
  }

  create() {
    this.scrollAnimation = gsap.timeline({
      repeat: -1
    });

    // another piece of awesome code here...
    this.addMouseEvents();
  }

  addMouseEvents() {
    if (this.eventsAlreadyAdded) return;
    this.el.addEventListener('mouseover', () => this.scrollAnimation.pause());
    this.el.addEventListener('mouseout', () => this.scrollAnimation.resume());
    this.eventsAlreadyAdded = true;
  }

  update() {
    if (this.scrollAnimation) {
      this.scrollAnimation.kill();
    }
    this.create();
  }
}

let scroll = null;
let windowResizeTimer = null;

document.addEventListener('DOMContentLoaded', () => {
  scroll = new Scroll(Scroll.element)
});

window.addEventListener('resize', () => {
  if (!scroll) return;
  if (windowResizeTimer) clearTimeout(windowResizeTimer);
  windowResizeTimer = setTimeout(() => { scroll.update(); }, 150);
});