J'essaie d'implémenter l'animation FLIP pour voir si je la comprends bien.
Dans ce codepen (excusez le mauvais code, je ne fais que déconner), si je commente le sommeil, la transition en douceur ne fonctionne plus. Le div change brusquement de position. C'est étrange car le temps de veille est de 0 ms.
import React, { useRef, useState } from "https://esm.sh/react@18"; import ReactDOM from "https://esm.sh/react-dom@18"; let first = {} let second = {} const sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const App = () => { const [start, setStart] = useState(true); const boxRefCb = async el => { if (!el) return; el.style.transition = ""; const x = parseInt(el?.getBoundingClientRect().x, 10); const y = parseInt(el?.getBoundingClientRect().y, 10); first = { x: second.x, y: second.y }; second = { x, y }; const dx = first.x - second.x; const dy = first.y - second.y; const transStr = `translate(${dx}px, ${dy}px)`; el.style.transform = transStr; await sleep(0); // comment me out el.style.transition = "transform .5s"; el.style.transform = ""; } return ( <> <div style={{ display: "flex", gap: "1rem", padding: "3rem"}}> <div ref={ start ? boxRefCb : null } style={{ visibility: start ? "" : "hidden", width: 100, height: 100, border: "solid 1px grey" }}></div> <div ref={ !start ? boxRefCb : null } style={{ visibility: !start ? "" : "hidden", width: 100, height: 100, border: "solid 1px grey" }}></div> </div> <button style={{ marginLeft: "3rem"}} onClick={() => setStart(start => !start)}>start | {start.toString()}</button> </> ); } ReactDOM.render(<App />, document.getElementById("root"))
Je soupçonne qu'il s'agit d'une magie de boucle d'événements que je ne comprends pas. Quelqu'un peut m'expliquer cela?
Vous utilisez une solution JavaScript normale à ce problème, mais React utilise un DOM virtuel et s'attend à ce que les éléments du DOM soient restitués lorsque l'état change. Par conséquent, je recommande d'utiliser l'état React pour mettre à jour la position XY des éléments dans le DOM virtuel, tout en utilisant CSS.
Démo fonctionnelle iciou le code peut être trouvé ici :
En
sleep
期间,浏览器可能有时间重新计算 CSSOM 框(也称为“执行回流”)。没有它,您的transform
, les règles ne s’appliquent pas vraiment.En fait, le navigateur attendra jusqu'à ce qu'il soit vraiment nécessaire pour appliquer vos modifications et mettre à jour l'intégralité du modèle de zone de page, car cela peut être très coûteux.
Quand tu fais quelque chose comme ça
Tous les CSSOM verront le dernier statut,
“绿色”
. Les deux autres ont été écartés.Donc, dans votre code, lorsque vous ne laissez pas la boucle de l'événement se boucler, vous ne verrez jamais non plus la valeur
transStr
.Cependant, s'appuyer sur 0ms
setTimeout
est un appel problématique, rien ne garantit que le style est recalculé à ce moment-là. Au lieu de cela, il est préférable de forcer un recalcul manuellement. Certaines méthodes/propriétés DOM le font de manière synchrone. Mais gardez à l'esprit que la redistribution peut être une opération très coûteuse, alors assurez-vous de l'utiliser de temps en temps, et s'il y a plusieurs endroits dans votre code qui nécessitent cette opération, assurez-vous de tous les connecter afin qu'une seule redistribution puisse être effectuée. p>