Cómo animar el elemento cuyo ancho y alto son automáticos (panel plegable)

El elemento cuyo atributo css es auto no se puede animar y la animación no tendrá ningún efecto, como el siguiente código:

.dropdown {
    
    
  transition: 0.2s;
  height: 0;
}
.dropdown.open {
    
    
  /* 高度发生了改变,但是没有动画. */
  height: auto;
}

Como todo el mundo sabe sobre el panel plegable, se espera que un elemento se pueda plegar y expandir sin problemas usando transiciones CSS, pero su tamaño expandido depende del contenido que contiene.

Se ha establecido la transición :, transition: 0.2spero la animación de expansión no tiene efecto. Se encuentra que este problema ocurre solo cuando la altitud se calcula automáticamente por auto. Porcentaje, valor de píxel, cualquier unidad absoluta puede funcionar normalmente. Pero todos estos deben establecer una altura específica de antemano en lugar de dejar que se determine naturalmente por el tamaño del contenido del elemento.

¿Por qué el navegador no soluciona este problema?

Según la documentación para desarrolladores de Mozilla, el valor automático se excluye intencionalmente de la especificación de la propiedad de animación de transición CSS. Consulte este documento para averiguar qué atributos son compatibles: portal . El contenido completo está aquí MDN: enlace

Todos conocemos el concepto de "reflujo". Volver a calcular el tamaño y la posición de todos los elementos consume mucho rendimiento en el navegador. Si desea hacer la transición de un elemento a la altura de automático, el navegador debe realizar un reflujo en cada etapa de la animación para determinar cómo deben moverse todos los demás elementos. No se puede almacenar en caché ni calcular de forma sencilla, porque cuando se expande, no se sabe a qué altura se puede expandir. Esto complicará los cálculos matemáticos que el navegador debe realizar entre bastidores y puede degradar el rendimiento de formas no evidentes.

¿Cómo resolver este problema? Aquí hay algunas ideas de implementación para su referencia.

Altura máxima

Como se mencionó anteriormente, los valores CSS solo se pueden convertir entre valores unitarios fijos. Pero supongamos que tenemos un elemento cuya altura se establece en auto, pero su altura máxima se establece en un valor fijo, como 1000px. No podemos convertir la altura, pero podemos convertir la altura máxima porque tiene un valor explícito. En cualquier momento, la altura real del elemento vendrá determinada por la altura máxima y la altura máxima. Entonces, siempre que el valor de la altura máxima sea mayor que el valor de auto, podemos convertir la altura máxima y obtener el efecto deseado.

Esto tiene dos desventajas clave: 1. La altura debe predecirse de antemano. 2. Se recomienda utilizar una animación uniforme.

transformar: scaleY ()

La implementación es así: establecemos una transformación para el atributo transform del elemento, y luego cambiamos entre transform: scaleY (1) y transform: scaleY (0). Esto significa, respectivamente, "presentar el elemento en la misma escala que al principio (en el eje y)" y "presentar el elemento con una escala de 0 (en el eje y)". La transición entre estos dos estados "exprimirá" hábilmente el tamaño natural del elemento y el tamaño basado en el contenido. ¿Cuales son las desventajas? Dado que no se activará el reflujo, los elementos que rodean este elemento no se verán afectados en absoluto. En otras palabras, cuando el elemento se expande, los siguientes elementos no se moverán hacia abajo.

Esta solución es adecuada para su uso en elementos de posicionamiento. Por ejemplo, el componente de selección en element-ui es una expansión desplegable basada en esta solución.

JavaScript

La última es la implementación de JS, el efecto también es el mejor, pero existen ciertas dificultades para implementar el código.

Si es absolutamente necesario realizar la transición de la parte contraída sin problemas, el tamaño de la expansión está completamente determinado por el contenido y otros elementos de la página se expandirán y contraerán automáticamente durante la transición, entonces puede usar algo de JavaScript para lograrlo.

<div class="container">
  <div class="section">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
  <div class="section collapsible">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
  </div>
  <div class="section">
   <p>Ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
</div>

<button id="toggle-button">Toggle collapse</button>

JS

function collapseSection(element) {
  var sectionHeight = element.scrollHeight;
  
  var elementTransition = element.style.transition;
  element.style.transition = '';
  
  requestAnimationFrame(function() {
    element.style.height = sectionHeight + 'px';
    element.style.transition = elementTransition;
    
    requestAnimationFrame(function() {
      element.style.height = 0 + 'px';
    });
  });
  
  element.setAttribute('data-collapsed', 'true');
}

function expandSection(element) {
  var sectionHeight = element.scrollHeight;
  element.style.height = sectionHeight + 'px';

  element.addEventListener('transitionend', function(e) {
    element.removeEventListener('transitionend', arguments.callee);
    element.style.height = null;
  });
  
  element.setAttribute('data-collapsed', 'false');
}

document.querySelector('#toggle-button').addEventListener('click', function(e) {
  var section = document.querySelector('.section.collapsible');
  var isCollapsed = section.getAttribute('data-collapsed') === 'true';
    
  if(isCollapsed) {
    expandSection(section)
    section.setAttribute('data-collapsed', 'false')
  } else {
    collapseSection(section)
  }
});

Finalmente, si está desarrollando usando Vue, necesita escribir un componente de panel plegable, puede consultar este artículo mío: Agregar descripción del enlace

Supongo que te gusta

Origin blog.csdn.net/wu_xianqiang/article/details/107055672
Recomendado
Clasificación