es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Javascript – Eliminar el escuchador de eventos cuando se redimensiona la pantalla.

Estoy trabajando para hacer que la navegación sea completamente accesible mediante el mouse, el teclado y el clic, dependiendo de la resolución.

Estoy buscando que en el móvil solo el clic funcione. Y el hover, clic y teclado para resoluciones más altas.

Edición importante:
Solo funciona perfectamente cuando cargue la página en la resolución correcta (baja o alta). PERO, si cambio el tamaño de la ventana, el removeEventListener no funciona.

Además, no sé si mi stopImmediatePropagation es la mejor solución para evitar múltiples funciones.

Aquí está la idea del código.

JS

window.addEventListener("DOMContentLoaded", onLoadFunction);

function onLoadFunction(e) {
  menu_burger();
  onResizeFunction(); //disparar la función de cambio de tamaño inmediatamente

  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();
  }
}

// FUNCIONES DE MENÚ
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('SOBRE DENTRO');
      e.stopImmediatePropagation();
    });

    subParent.addEventListener('mouseout', function(e) {
      subParent.setAttribute('aria-expanded', 'false');
      console.log('SOBRE FUERA');
      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('CLIC');
      e.stopImmediatePropagation();
    });
  })
}

function menu_onFocus() {
  focusEntry.forEach(sub => {
    var subParent = sub.parentElement;
    sub.addEventListener('keyup', (e) => {
      console.log('TOQUE');
      if (e.keyCode === 27) {
        console.log('ESC');
        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('ENFOQUE');
      e.stopImmediatePropagation();
    });

    subParent.addEventListener('focusout', function (e) {
      console.log('FOCO FUERA');
      //console.log(e.relatedTarget); //objetivo actual
      if (!subParent.contains(e.relatedTarget)) {
        subParent.setAttribute('aria-expanded', 'false');
      }
      e.stopImmediatePropagation();
    });
  })
}

Intenté algo así, pero no funcionó:

function menu_onFocusDetection() {
  focusDetectionEntry.forEach(sub => {
    var subParent = sub.parentElement;
    //si el enfoque está en el botón, modificamos su padre
    function test(ev) {
      subParent.setAttribute('aria-expanded', 'true');
      console.log('ENFOQUE');
      ev.stopImmediatePropagation();
    }


    //si el enfoque sale de li
    function test2(ev2) {
      // console.log(ev2.relatedTarget); //objetivo actual
      console.log('ENFOQUE FUERA');
      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);
    }
  })

}
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Mejora de la accesibilidad de navegación en diferentes resoluciones

    Para hacer la navegación completamente accesible a través del ratón, teclado y clic según la resolución, el código proporcionado tiene varias funciones que atienden a diferentes eventos. A resoluciones por debajo de 770 píxeles, solo funciona el clic, mientras que a resoluciones de 770 píxeles o más, funciona el pasar el ratón por encima, el clic y el teclado.

    Sin embargo, una edición importante menciona que el código no funciona perfectamente cuando se redimensiona la página en vivo. El removeEventListener utilizado para eliminar los escuchadores de eventos no funciona en estos casos. Además, el uso de stopImmediatePropagation para prevenir funciones múltiples no se confirma como la solución mejor.

    Para rectificar el problema, necesitamos examinar las funciones utilizadas y considerar un enfoque diferente. Una posible solución es proporcionar una consulta de medios en el archivo CSS que establezca aria-expanded en false cuando la resolución es menor a 770 píxeles. Luego, podemos eliminar las condiciones if-else en menu_onClick() y onResizeFunction() que verifican la resolución y eliminan los escuchadores de eventos.

    En menu_onClick(), podemos eliminar e.stopImmediatePropagation() que previene múltiples funciones, ya que no lo hemos confirmado como una solución mejor. Del mismo modo, también podemos eliminar e.stopImmediatePropagation() en todas las demás funciones.

    A continuación, en lugar de utilizar funciones separadas para diferentes eventos, podemos utilizar la delegación de eventos y capturar los eventos a nivel del contenedor principal. Este enfoque hace que sea más fácil y eficiente administrar los eventos.

    Aquí está el código revisado con los cambios descritos anteriormente:

    JS

    window.addEventListener("DOMContentLoaded", onLoadFunction);
    
    function onLoadFunction(e) {
      menu_burger();
    }
    
    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');
      });
    
      document.querySelector('.nav-list').addEventListener('click', function (e) {
        if (e.target.tagName === 'BUTTON') {
          let attrState = e.target.parentElement.getAttribute('aria-expanded');
    
          if (attrState === 'false') {
            e.target.parentElement.setAttribute('aria-expanded', 'true');
          } else if (attrState === 'true') {
            e.target.parentElement.setAttribute('aria-expanded', 'false');
          }
        }
      });
    
      document.querySelector('.nav-list').addEventListener('mouseover', function (e) {
        if (window.innerWidth > 770 && e.target.tagName === 'BUTTON') {
          e.target.parentElement.setAttribute('aria-expanded', 'true');
          console.log('OVER IN');
        }
      });
    
      document.querySelector('.nav-list').addEventListener('mouseout', function (e) {
        if (window.innerWidth > 770 && e.target.tagName === 'BUTTON') {
          e.target.parentElement.setAttribute('aria-expanded', 'false');
          console.log('OVER OUT');
        }
      });
    
      document.querySelector('.nav-list').addEventListener('keyup', function (e) {
        if (e.keyCode === 27 && e.target.tagName === 'BUTTON') {
          console.log('ECHAP');
          e.target.parentElement.setAttribute('aria-expanded', 'false');
        }
      });
    
      document.querySelector('.nav-list').addEventListener('focusin', function (e) {
        if (window.innerWidth > 770 && e.target.tagName === 'BUTTON') {
          e.target.parentElement.setAttribute('aria-expanded', 'true');
          console.log('FOCUS');
        }
      });
    
      document.querySelector('.nav-list').addEventListener('focusout', function (e) {
        if (window.innerWidth > 770 && e.target.tagName === 'BUTTON' && !e.relatedTarget.closest('.nav-list')) {
          console.log('FOCUS OUT');
          e.target.parentElement.setAttribute('aria-expanded', 'false');
        }
      });
    }
    

    Con estos cambios, hemos simplificado el código y mejorado su funcionalidad. La consulta de medios en el archivo CSS sería la siguiente:

    @media screen and (max-width: 770px) {
      .nav-list > li[aria-expanded="true"] {
        aria-expanded: false;
      }
    }
    

    Esto asegurará que aria-expanded siempre sea false cuando la resolución sea inferior a 770 píxeles.

Comments are closed.