Javascript - 在调整大小时删除事件侦听器

Javascript - Remove event listener at resize

我正在做一些工作,使导航完全可以通过鼠标悬停、键盘和单击来访问,具体取决于分辨率。

我正在移动设备上寻找,只有点击有效。悬停、单击、键盘以获得更高的分辨率。

重要编辑: 它仅在我以正确的分辨率(低或高)加载页面时 完美 工作。 但是,如果我实时调整大小,removeEventListener 将不起作用。

加:我不知道我的stopImmediatePropagation是否是避免多重功能的更好解决方案。

这里是代码的思路。

JS

window.addEventListener("DOMContentLoaded", onLoadFunction);

function onLoadFunction(e) {
  menu_burger();
  onResizeFunction(); //trigger resize function immediately

  window.addEventListener("resize", onResizeFunction);
}

function onResizeFunction(e) {
  if (window.innerWidth > 770) {
    window.removeEventListener('resize', menu_onClick);
    menu_onClick();
    menu_mouseOver();
    menu_onFocus();
    menu_onFocusDetection();
  } else {
    window.removeEventListener('resize', menu_onClick);
    window.removeEventListener('resize', menu_mouseOver);
    window.removeEventListener('resize', menu_onFocusDetection);
    window.removeEventListener('resize', menu_onFocus);
    menu_onClick();
  }
}

// FONCTIONS MENU
const focusDetectionEntry = document.querySelectorAll('.nav-list--focus-detection > li[aria-expanded] > button');
const focusEntry = document.querySelectorAll('.nav-list--focus > li[aria-expanded] > button');
const overEntry = document.querySelectorAll('.nav-list--over > li[aria-expanded] > button');
const clickEntry = document.querySelectorAll('.nav-list--click > li[aria-expanded] > button');

function menu_burger() {
  document.querySelector('.menu-burger').addEventListener('click', function () {
    this.classList.toggle('menu--open');
    document.querySelector('.main-nav-list').classList.toggle('main-nav-list--open');
  });
}

function menu_mouseOver() {
  overEntry.forEach(sub => {
    var subParent = sub.parentElement;
    subParent.addEventListener('mouseover', function(e) {
      subParent.setAttribute('aria-expanded', 'true');
      console.log('OVER IN');
      e.stopImmediatePropagation();
    });

    subParent.addEventListener('mouseout', function(e) {
      subParent.setAttribute('aria-expanded', 'false');
      console.log('OVER OUT');
      e.stopImmediatePropagation();
    });
  })
}

function menu_onClick() {
  clickEntry.forEach(sub => {
    var subParent = sub.parentElement;
    sub.addEventListener('click', function(e) {
      let attrState = subParent.getAttribute('aria-expanded');

      if (attrState === 'false') {
        subParent.setAttribute('aria-expanded', 'true')
      } else if (attrState === 'true') {
        subParent.setAttribute('aria-expanded', 'false');
      }

      console.log('CLICK');
      e.stopImmediatePropagation();
    });
  })
}

function menu_onFocus() {
  focusEntry.forEach(sub => {
    var subParent = sub.parentElement;
    sub.addEventListener('keyup', (e) => {
      console.log('TOUCHE');
      if (e.keyCode === 27) {
        console.log('ECHAP');
        subParent.setAttribute('aria-expanded', 'false');
      }
      e.stopImmediatePropagation();
    });
  })
}

function menu_onFocusDetection() {
  focusDetectionEntry.forEach(sub => {
    var subParent = sub.parentElement;
    sub.addEventListener('focus', function (e) {
      subParent.setAttribute('aria-expanded', 'true');
      console.log('FOCUS');
      e.stopImmediatePropagation();
    });

    subParent.addEventListener('focusout', function (e) {
      console.log('FOCUS OUT');
      //console.log(e.relatedTarget); //target actuel
      if (!subParent.contains(e.relatedTarget)) {
        subParent.setAttribute('aria-expanded', 'false');
      }
      e.stopImmediatePropagation();
    });
  })
}

我试过类似的东西,但没有成功:

function menu_onFocusDetection() {
  focusDetectionEntry.forEach(sub => {
    var subParent = sub.parentElement;
    // si focus sur le bouton, on modifie sont parent
    function test(ev) {
      subParent.setAttribute('aria-expanded', 'true');
      console.log('FOCUS');
      ev.stopImmediatePropagation();
    }


    // si le focus sort du li
    function test2(ev2) {
      // console.log(ev2.relatedTarget); //target actuel
      console.log('FOCUS OUT');
      if (!subParent.contains(ev2.relatedTarget)) {
        subParent.setAttribute('aria-expanded', 'false');
      }
      ev2.stopImmediatePropagation();
    }

    if (window.innerWidth > 770) {
      sub.addEventListener('focus', test);
      sub.addEventListener('focusout', test2);
    } else {
      sub.removeEventListener('focus', test);
      sub.removeEventListener('focusout', test2);
    }
  })

}

事件处理程序在每次事件发生时执行,而不仅仅是第一次。他们只需要注册一次。

将点击和鼠标悬停处理程序移至独立函数声明,并在外部块中注册这些处理程序。所以基本上:

window.addEventListener("load", onLoadFunction);

function onLoadFunction(e) {
  onResizeFunction();// trigger resize function immediately

  window.addEventListener("resize", onResizeFunction);
}

function onResizeFunction(e) {
  if (window.innerWidth > 770) {
    //over + click
    over();
    click();
  } else {
    //only click
    click();
  }

}

function click() {
  console.log('CLICK');
}
  
function over() {
  console.log('OVER');
}

document.querySelector('.test').addEventListener('click', click);
document.querySelector('.test').addEventListener('mouseover', over);

好的,这就是答案:

我不得不拆分我的函数并在每个函数中执行条件。

window.addEventListener("DOMContentLoaded", onLoadFunction);
function onLoadFunction(e) {
  onResizeFunction(); //trigger resize function immediately
  window.addEventListener("resize", onResizeFunction);
}

function onResizeFunction(e) {
  menu_onFocusDetection();
}

function initEntries() {
  focusDetectionEntry = document.querySelectorAll('.nav-list--focus-detection > li[aria-expanded] > button');
}

function focus(e) {
  this.parentElement.setAttribute('aria-expanded', 'true');
  e.stopImmediatePropagation();
}

function menu_onFocusDetection() {
  focusDetectionEntry.forEach(sub => {
    var subParent = sub.parentElement;
    if (window.innerWidth > 770) {
      sub.addEventListener('focus', focus);
      subParent.addEventListener('focusout', focusOut);
    } else {
      sub.removeEventListener('focus', focus);
      subParent.removeEventListener('focusout', focusOut);
    }
  });
}