[Diccionario front-end] Comparación de 4 (+1) métodos de implementación de techo móvil [Versión de actualización de rendimiento]

Vista previa de la versión modificada

Este artículo fue escrito hace tres días y algunos grandes me dieron algunas sugerencias de enmiendas, creo que esta opinión es realmente relevante. Entonces hay una versión modificada de esta actualización. El código se actualiza a GitHub de forma sincrónica.

El contenido revisado es el siguiente:

  1. Se agregaron descripciones gráficas para explicar intuitivamente el significado de la colección getBoundingClientRect ()

  2. Cómo evitar los frecuentes riesgos de reflujo (optimizar el seguimiento de la rodadura)

  3. Supervisión de los problemas de rendimiento causados ​​por el desplazamiento (usando IntersectionObserver, nueva solución)

El contenido revisado y actualizado está en los puntos 4 y 5. Si ha leído este artículo, puede ver directamente el contenido revisado y actualizado. O puedes verlo de nuevo.

Prefacio

La primera solicitud que recibí de la segunda empresa a la que me uní fue la de reparar el efecto de techo rodante que anteriormente se subcontrataba. Me preguntaba por qué hay un error en un techo de desplazamiento. Más tarde verifiqué el código y descubrí que el atributo offsetTop se usó directamente y no se realizó ningún tratamiento de compatibilidad.

offsetTop

Se utiliza para obtener la distancia (valor de compensación) desde el elemento actual hasta la parte superior del padre de posicionamiento (element.offsetParent).

La definición de posicionamiento padre offsetParent es: el elemento padre de la posición más cercana! = Estático al elemento actual.

Quizás la persona que escribió este código no se dio cuenta de la condición secundaria de "localizar al padre".

Más adelante, en el proyecto, siempre habrá el efecto del techo rodante que debe realizarse. Ahora daré una introducción detallada a los 4 métodos de techo rodante que conozco.

Tabla de contenido

  1. Posición de uso: pegajosa para lograr

  2. Utilice la implementación superior offset (). De JQuery

  3. Utilice la implementación nativa offsetTop

  4. Utilice obj.getBoundingClientRect (). Top para lograr

  5. Optimización del rendimiento

¿Entiende los cuatro métodos anteriores? El código relevante se ha subido a GitHub y los interesados ​​pueden clonar el código y ejecutarlo localmente. Espero dar un apoyo estrella.

Cuatro formas de lograr

Primero echemos un vistazo a las representaciones:

[Diccionario front-end] Comparación de 4 (+1) métodos de implementación de techo móvil [Versión de actualización de rendimiento]

Uno, posición de uso: pegajosa para lograr

1. ¿Qué es el posicionamiento fijo?

El posicionamiento fijo es equivalente a la combinación de posicionamiento relativo relativo y posicionamiento fijo; durante el proceso de desplazamiento de los elementos de la página, cuando la distancia entre un elemento y su elemento principal alcanza el requisito de posicionamiento fijo; el efecto relativo del posicionamiento relativo del elemento se convierte en un posicionamiento fijo fijo Efecto.

Portal de MDN

2. ¿Cómo se usa?

Condiciones de Uso:

  1. El elemento padre no puede tener desbordamiento: oculto o desbordamiento: atributos automáticos

  2. Debe especificar uno de los 4 valores superior, inferior, izquierdo, derecho; de lo contrario, solo estará en posición relativa

  3. La altura del elemento principal no puede ser menor que la altura del elemento adhesivo

  4. El elemento adhesivo solo tiene efecto dentro de su elemento principal

Este efecto se puede lograr agregando los siguientes estilos a los elementos que deben desplazarse y al techo:

.sticky {

    position: -webkit-sticky;

    position: sticky;

    top: 0;

}

3. ¿Es este atributo fácil de usar?

Echemos un vistazo a la compatibilidad de este atributo en ¿Puedo usar? Podemos
[Diccionario front-end] Comparación de 4 (+1) métodos de implementación de techo móvil [Versión de actualización de rendimiento]
ver que la compatibilidad de este atributo no es muy buena, porque esta API es solo un atributo experimental. Sin embargo, la compatibilidad de esta API en el sistema IOS sigue siendo relativamente buena.

Por lo tanto, si usamos esta API en un entorno de producción, generalmente la usaremos en combinación con los siguientes métodos.

En segundo lugar, use la implementación offset (). Top de JQuery

Sabemos que JQuery encapsula la API para manipular DOM y leer las propiedades de cálculo de DOM. Basado en la combinación de offset (). Top y scrollTop (), también podemos lograr el efecto de desplazamiento de techo.

...

window.addEventListener('scroll', self.handleScrollOne);

...

handleScrollOne: function() {

    let self = this;

    let scrollTop = $('html').scrollTop();

    let offsetTop = $('.title_box').offset().top;

    self.titleFixed = scrollTop > offsetTop;

}

...

Esto es ciertamente posible, pero dado que JQuery se está retirando lentamente de la etapa de la historia, intentamos no usar la API de JQuery en el código. Podemos manejar el offsetTop nativo nosotros mismos basándonos en el código fuente de offset (). Top. Entonces hay una tercera forma.

scrolloTop () tiene problemas de compatibilidad. En los navegadores WeChat, IE y algunas versiones de Firefox, el valor de $ ('html'). scrollTop () será 0, por lo que casi no hay compatibilidad del tercer esquema. .

En tercer lugar, use la implementación nativa offsetTop

Sabemos que offsetTop es el desplazamiento relativo al padre de posicionamiento. Si el elemento que necesita desplazarse hacia la parte superior parece posicionar el elemento padre, entonces offsetTop no obtiene la distancia entre el elemento y la parte superior de la página.

Podemos hacer el siguiente procesamiento en offsetTop nosotros mismos:

getOffset: function(obj,direction){

    let offsetL = 0;

    let offsetT = 0;

    while( obj!== window.document.body && obj !== null ){

        offsetL += obj.offsetLeft;

        offsetT += obj.offsetTop;

        obj = obj.offsetParent;

    }

    if(direction === 'left'){

        return offsetL;

    }else {

        return offsetT;

    }

}

utilizar:

...

window.addEventListener('scroll', self.handleScrollTwo);

...

handleScrollTwo: function() {

    let self = this;

    let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;

    let offsetTop = self.getOffset(self.$refs.pride_tab_fixed);

    self.titleFixed = scrollTop > offsetTop;

}

...

¿Ve algunos problemas con los dos métodos anteriores?

¿Necesitamos usar el valor de scrollTop-offsetTop para lograr el efecto de desplazamiento del techo? la respuesta es negativa.

Veamos juntos la cuarta opción.

Cuarto, use obj.getBoundingClientRect (). Top para lograr

definición:

Esta API puede indicarle la distancia de un elemento en la página en relación con la ventana del navegador.

utilizar:

Para el techo de la pestaña, puede usar obj.getBoundingClientRect (). Top en lugar de scrollTop-offsetTop, el código es el siguiente:

// html

<div class="pride_tab_fixed" ref="pride_tab_fixed">

    <div class="pride_tab" :class="titleFixed == true ? 'isFixed' :''">

        // some code

    </div>

</div>

// vue

export default {

    data(){

      return{

        titleFixed: false

      }

    },

    activated(){

      this.titleFixed = false;

      window.addEventListener('scroll', this.handleScroll);

    },

    methods: {

      //滚动监听,头部固定

      handleScroll: function () {

        let offsetTop = this.$refs.pride_tab_fixed.getBoundingClientRect().top;

        this.titleFixed = offsetTop < 0;

        // some code

      }

    }

  }

La diferencia entre offsetTop y getBoundingClientRect ()

1. getBoundingClientRect ():

Se utiliza para obtener la posición de la parte izquierda, superior, derecha e inferior de un elemento en la página en relación con la ventana del navegador. No incluye la parte enrollada del documento.

[Diccionario front-end] Comparación de 4 (+1) métodos de implementación de techo móvil [Versión de actualización de rendimiento]

Esta función devuelve un objeto objeto con 8 atributos: superior, derecha, inferior, izquierda, ancho, alto, x, y
[Diccionario front-end] Comparación de 4 (+1) métodos de implementación de techo móvil [Versión de actualización de rendimiento]

2. offsetTop:

Se utiliza para obtener la distancia (valor de compensación) desde el elemento actual hasta la parte superior del padre de posicionamiento (element.offsetParent).

La definición de posicionamiento padre offsetParent es: el elemento padre de la posición más cercana! = Estático al elemento actual.

Los métodos offsetTop y offsetParent se combinan para obtener la distancia desde el elemento hasta el margen superior del cuerpo. el código se muestra a continuación:

getOffset: function(obj,direction){

    let offsetL = 0;

    let offsetT = 0;

    while( obj!== window.document.body && obj !== null ){

        offsetL += obj.offsetLeft;

        offsetT += obj.offsetTop;

        obj = obj.offsetParent;

    }

    if(direction === 'left'){

        return offsetL;

    }else {

        return offsetT;

    }

}

Conocimiento extendido

offsetWidth:

El tamaño del espacio ocupado por el elemento en la dirección horizontal:
offsetWidth = border-left + padding-left + width + padding-right + border-right

offsetHeight:

El tamaño del espacio ocupado por el elemento en la dirección vertical:
offsetHeight = border-top + padding-top + height + padding-bottom + border-bottom

Nota: Si hay una barra de desplazamiento vertical, offsetWidth también incluye el ancho de la barra de desplazamiento vertical; si hay una barra de desplazamiento horizontal, offsetHeight también incluye la altura de la barra de desplazamiento horizontal;

offsetTop:

La distancia de píxeles entre el borde exterior superior del elemento y el borde interior superior del elemento offsetParent;

offsetLeft:

La distancia en píxeles desde el borde exterior izquierdo del elemento al borde interior izquierdo del elemento offsetParent;

Precauciones

  1. Todos los atributos de compensación son de solo lectura;

  2. Si display: none se establece para el elemento, su atributo de desplazamiento es todo 0;

  3. Cada vez que acceda al atributo de compensación, debe volver a calcular (guardar la variable);

  4. Al usarlo, puede parecer que el DOM no está inicializado y el atributo se lee. En este momento, se devolverá 0; para este problema, debemos esperar hasta que se inicialice el elemento DOM antes de ejecutar.

Dos problemas encontrados

1. El momento de succión se acompaña de fluctuación

La razón de la fluctuación es porque: cuando la posición del elemento superior se vuelve fija, el elemento está fuera del flujo de documentos y el siguiente elemento se llena. Es esta operación de llenado de bits la que causa la fluctuación.

solución

Agregue un elemento principal de igual altura a este elemento de techo. Supervisamos el valor superior getBoundingClientRect (). De este elemento principal para lograr el efecto de techo, a saber:

<div class="title_box" ref="pride_tab_fixed">

    <div class="title" :class="titleFixed == true ? 'isFixed' :''">

    使用 `obj.getBoundingClientRect().top` 实现

    </div>

</div>

Esta solución puede resolver el error de jitter.

En segundo lugar, el efecto techo no se puede responder a tiempo

Este problema es mi dolor de cabeza, antes no me importaba. No presté atención a este problema hasta que un día usé Meituan para pedir comida para llevar.

descripción:

  1. Cuando la página se desplaza hacia abajo, el elemento de techo debe esperar a que se detenga el desplazamiento de la página antes de que aparezca el efecto de techo.

  2. Cuando la página se desplaza hacia arriba, el elemento de techo no volverá a su forma original cuando se desplaza hacia el elemento de techo para restaurar la posición del flujo de documentos, pero volverá a su forma original después de que la página deje de desplazarse

Razón: El evento de monitoreo de desplazamiento no se puede monitorear en tiempo real en el sistema ios y sus eventos relacionados se activan cuando el desplazamiento se detiene.

solución:

¿Recuerda la posición: pegajosa en el primer esquema? Este atributo tiene buena compatibilidad en sistemas superiores a IOS6, por lo que podemos distinguir entre dispositivos IOS y Android para hacer dos procesamientos.

IOS usa position: sticky y Android usa el desplazamiento para monitorear el valor de getBoundingClientRect (). Top.

¿Qué pasa si la versión de IOS es demasiado baja? Aquí hay una idea: window.requestAnimationFrame ().

Optimización del rendimiento (nuevo)

Hasta ahora, la introducción del método de techo rodante en 4 ha terminado, pero ¿esto realmente ha terminado? De hecho, todavía hay margen de optimización.

Hacemos la optimización del rendimiento desde dos direcciones (de hecho, una dirección):

  1. Evite el reflujo excesivo

  2. Optimice los eventos de monitoreo de desplazamiento

Proceso de localización de problemas

Sabemos que el reflujo excesivo degradará el rendimiento de la página. Por lo tanto, debemos reducir la cantidad de reflujos tanto como sea posible para brindar a los usuarios una sensación más suave.

Algunos amigos pueden decir que lo sé, pero ¿qué tiene esto que ver con el techo rodante?

No hay prisa, ¿recuerdas que el techo de desplazamiento usó offsetTop o getBoundingClientRect (). Top para obtener el desplazamiento de la respuesta?

Dado que hay atributos del elemento leído, naturalmente hará que la página se reajuste.

Por lo tanto, la dirección de nuestra optimización es comenzar reduciendo la cantidad de veces para leer los atributos del elemento. Verifique el código y descubra que cuando se activa el evento de desplazamiento de pantalla, se llamará al método relevante para leer el desplazamiento del elemento.

Mejoramiento

Hay dos soluciones para este problema:

  1. Sacrifique la suavidad para cumplir con el rendimiento y utilice la aceleración para controlar la invocación de métodos relacionados

  2. El uso de IntersectionObserver combinado con la aceleración también sacrifica la suavidad.

La primera opcion

Esta solución es muy común, pero sus efectos secundarios también son obvios, es decir, el efecto techo se retrasará algo, si el producto es aceptable, puede ser un buen método.

Esto puede controlar solo la lectura dentro de un cierto período de tiempo

La función del acelerador aquí es directamente el método del acelerador encapsulado en lodash.js.

el código se muestra a continuación:

window.addEventListener('scroll', _.throttle(self.handleScrollThree, 50));

La segunda opción

La segunda solución es relativamente fácil de aceptar, es decir, para admitir IntersectionObserver, use IntersectionObserver, de lo contrario, use throttle.

Hablemos primero de IntersectionObserver

IntersectionObserver puede usarse para monitorear si el elemento ingresa al área visual del dispositivo, sin cálculos frecuentes para realizar este juicio.

A través de este atributo, no podemos leer la posición relativa del elemento cuando el elemento no está en el rango visible, lo que ha logrado una optimización del rendimiento; cuando el navegador no admita este atributo, use el acelerador para procesar.

Echemos un vistazo a la compatibilidad de este atributo:
[Diccionario front-end] Comparación de 4 (+1) métodos de implementación de techo móvil [Versión de actualización de rendimiento]
probablemente admita más del 60% y aún se puede usar en el proyecto (debe realizar un procesamiento de compatibilidad).

Para saber cómo usar IntersectionObserver, consulte el tutorial de MDN o Ruan Yifeng.

El código optimizado usando IntersectionObserver y throttle es el siguiente:

IntersectionObserverFun: function() {

    let self = this;

    let ele = self.$refs.pride_tab_fixed;

    if( !IntersectionObserver ){

        let observer = new IntersectionObserver(function(){

            let offsetTop = ele.getBoundingClientRect().top;

            self.titleFixed = offsetTop < 0;

        }, {

            threshold: [1]

        });

        observer.observe(document.getElementsByClassName('title_box')[0]);

    } else {

        window.addEventListener('scroll', _.throttle(function(){

            let offsetTop = ele.getBoundingClientRect().top;

            self.titleFixed = offsetTop < 0;

        }, 50));

    }

}, 

Nota

La API IntersectionObserver es asincrónica y no se activa de forma sincrónica con el desplazamiento del elemento de destino.

La especificación establece que la implementación de IntersectionObserver debe usar requestIdleCallback (). No ejecutará la devolución de llamada inmediatamente, llamará a window.requestIdleCallback () para ejecutar de forma asincrónica la función de devolución de llamada que especifiquemos, y también estipula que el tiempo máximo de retraso es de 100 milisegundos.

para resumir:

Esta combinación de IntersectionObserver y throttle es una solución alternativa. La ventaja de esta solución es que puede reducir efectivamente el riesgo de reflujo de la página, pero también hay desventajas y la suavidad de la página debe sacrificarse. La elección específica depende de las necesidades de la empresa.

Serie de diccionarios front-end

La serie "Diccionario de interfaz de usuario" seguirá actualizándose. En cada número, hablaré de un punto de conocimiento que aparece con frecuencia. Espero que encuentres algún lugar impreciso o incorrecto en el texto durante el proceso de lectura, te estaré muy agradecido, si puedes ganar algo con esta serie, también estaré muy feliz.

Contenido: La introducción de puntos de conocimiento relacionados con el front-end y la red, con aplicación práctica como ayuda.

Propósito: Esta serie de artículos puede ayudar un poco a los lectores y resolver algunas confusiones.

Espero que pueda darme algunos consejos y sugerencias.

Si crees que mi artículo está bien escrito, sígueme.

Supongo que te gusta

Origin blog.51cto.com/15077552/2596500
Recomendado
Clasificación