Este es un proyecto de Javascript, utilizando la biblioteca jQuery.
Tengo una barra adhesiva que me gustaría mostrar siempre que la ventana del navegador esté debajo de una determinada posición de página y, de lo contrario, ocultarla. Su ID es #sticky-atc-bar .
La posición de la página está determinada por la parte superior de un elemento con clase .product-section .
Basado en la investigación sobre cómo hacer esto, originalmente se me ocurrió el siguiente JS.
$( document ).ready(function() { $('#sticky-atc-bar').hide(); var section = $(".product-section"); var offsetSection = section.offset().top; //check for top property $(function() { $(window).scroll(function() { console.log('Scroll Event'); if ($(window).scrollTop() >= offsetSection) { // reached product section console.log('True:'); $('#sticky-atc-bar').show(); } else { // not reached product section console.log('False'); $('#sticky-atc-bar').hide(); } }); }); });Esto funciona. Sin embargo, soy consciente de que genera una gran cantidad de eventos de desplazamiento, todo el tiempo que el usuario interactúa con la página. Sabiendo que eso es muy ineficiente, busqué enfoques alternativos. En el camino leí este artículo llamado "Aprendiendo de Twitter", que tenía mucho sentido.
También encontré esta solución para un requisito similar. Mi versión de ese código es:
var target = $(".product-section").offset().top, timeout = null; $('#sticky-atc-bar').hide(); $(window).scroll(function () { if (!timeout) { timeout = setTimeout(function () { console.log('scroll'); clearTimeout(timeout); timeout = null; if ($(window).scrollTop() >= target) { $('#sticky-atc-bar').show(); } else { $('#sticky-atc-bar').hide(); } }, 250); } });Lo configuré en este jsFiddle y funciona.
Sin embargo... Todavía genera un número significativo de eventos. Simplemente se han reducido a un evento cada 250 ms, es decir, 4 cada segundo.
Lo que me gustaría saber es si hay una mejor manera de hacerlo. Dicho de otra manera, además de cambiar el tiempo de espera en esta segunda pieza de código, ¿puedo reducir esta operación a incluso menos eventos? ¿Y es eso necesario en este punto, o un evento cada 250 ms no es un impacto significativo?
Aquí tienes: https://jsfiddle.net/son0azfj/
var productEl = document.querySelector('.product-section') var stickyEl = document.querySelector('#sticky-atc-bar') // check if we have elements if (productEl && stickyEl) { // create an observer object, binding toggleDisplayFactory to it var observer = new IntersectionObserver(toggleDisplayFactory(stickyEl)) // observe the product element observer.observe(productEl) } // [1] create a named function which accepts an element... function toggleDisplayFactory(element) { // and returns a function - the handler that IntersectionObserver expects return function handler(entries) { // determine if the observed element is in the viewport or not var isInViewPort = Boolean(entries.find(entry => entry.intersectionRatio > 0)) /** * if in the viewport: * we want the element passed in at [1] to use it's own styles, ie remove the inline style property * else: * we want the element to inherit its default display property (eg block, inline, inline-block, etc.) and thus be visible */ var display = isInViewPort ? null : 'inherit' // set the display property of the element passed in at [1] element.style.display = display } }InterSectionObserver para observar la posición de un elemento con respecto a la ventana gráfica. Use la posición de ese elemento en la ventana gráfica para "hacer otra cosa", es decir, mostrar/ocultar otro elementosetTimeout para manipular el DOM; use requestAnimationFrame en su lugar (no es necesario aquí)Razonamiento:
IntersectionObserver le permite observar un elemento arbitrario con respecto a su posición en la ventana gráfica, en lugar de un evento de desplazamiento que se activa rápidamente a medida que uno se desplaza. Los eventos que activa un elemento observado solo se activan cuando cambia su posición relativa a la ventana gráfica
setTimeout : si tuviera que usar un tiempo de espera, necesitaría pensar en algún número que sea apropiado para usar al usar setTimeout . ¿Cómo haces esto? Bueno, solo puedes adivinar... tendrías que usar un número mágico. requestAnimationFrame en cambio sabe cuándo el DOM está listo para volver a renderizar y calcular el diseño, no se requieren números mágicos
Enlaces:
EDITAR: Siéntase libre de reemplazar document.querySelector con $(selector) - el resto del código funcionará como está.