Rumah > Soal Jawab > teks badan
Saya cuba melaksanakan animasi FLIP untuk melihat sama ada saya memahaminya dengan betul.
Dalam codepen ini (maafkan kod buruk, saya hanya mengacau), jika saya mengulas tidur, peralihan yang lancar tidak lagi berfungsi. Div bertukar kedudukan secara tiba-tiba. Ini pelik kerana masa tidur ialah 0ms.
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"))
Saya mengesyaki ini adalah sihir gelung peristiwa yang saya tidak faham. Bolehkah seseorang menjelaskan perkara ini kepada saya?
P粉0222857682024-04-07 14:25:14
Anda menggunakan penyelesaian JavaScript biasa untuk masalah ini, tetapi React menggunakan DOM maya dan menjangkakan elemen DOM akan dipaparkan semula apabila keadaan berubah. Oleh itu, saya mengesyorkan memanfaatkan keadaan React untuk mengemas kini kedudukan XY elemen dalam DOM maya, tetapi masih menggunakan CSS.
Demo kerja di siniatau kod boleh didapati di sini:
import { useState, useRef, useLayoutEffect } from "react"; import "./styles.css"; type BoxXYPosition = { x: number; y: number }; export default function App() { const startBox = useRef(null); const startBoxPosition = useRef ({ x: 0, y: 0 }); const endBox = useRef (null); const [boxPosition, setBoxPosition] = useState ({ x: 0, y: 0 }); const { x, y } = boxPosition; const hasMoved = Boolean(x || y); const updatePosition = () => { if (!endBox.current) return; const { x: endX, y: endY } = endBox.current.getBoundingClientRect(); const { x: startX, y: startY } = startBoxPosition.current; // "LAST" - calculate end position const moveXPosition = endX - startX; const moveYPosition = endY - startY; // "INVERT" - recalculate position based upon current x,y coords setBoxPosition((prevState) => ({ x: prevState.x !== moveXPosition ? moveXPosition : 0, y: prevState.y !== moveYPosition ? moveYPosition : 0 })); }; useLayoutEffect(() => { // "FIRST" - save starting position if (startBox.current) { const { x, y } = startBox.current.getBoundingClientRect(); startBoxPosition.current = { x, y }; } }, []); // "PLAY" - switch between start and end animation via the x,y state and a style property return ( ); } Transition Between Points
{hasMoved ? "End" : "Start"}
P粉1067114252024-04-07 09:16:56
Dalam sleep
期间,浏览器可能有时间重新计算 CSSOM 框(也称为“执行回流”)。没有它,您的 transform
peraturan tidak benar-benar terpakai.
Malah, penyemak imbas akan menunggu sehingga ia benar-benar diperlukan untuk menggunakan perubahan anda dan mengemas kini keseluruhan model kotak halaman, kerana berbuat demikian boleh menjadi sangat mahal.
Apabila anda melakukan sesuatu seperti ini
element.style.color = "red"; element.style.color = "yellow"; element.style.color = "green";
Semua CSSOM akan melihat status terkini, “绿色”
. Dua lagi dibuang.
Jadi dalam kod anda, apabila anda tidak membiarkan gelung acara benar-benar gelung, anda tidak akan melihat nilai transStr
sama ada.
Namun, bergantung pada 0ms setTimeout
adalah panggilan masalah, tiada apa-apa untuk memastikan gaya dikira semula pada masa itu. Sebaliknya, lebih baik untuk memaksa pengiraan semula secara manual. Beberapa kaedah/sifat DOM melakukan ini secara serentak. Tetapi perlu diingat bahawa aliran semula boleh menjadi operasi yang sangat mahal, jadi pastikan anda menggunakannya sekali-sekala, dan jika terdapat berbilang tempat dalam kod anda yang memerlukan operasi ini, pastikan anda menyambung semuanya supaya aliran semula tunggal boleh dilakukan. p>
const el = document.querySelector(".elem"); const move = () => { el.style.transition = ""; const transStr = `translate(150px, 0px)`; el.style.transform = transStr; const forceReflow = document.querySelector("input").checked; if (forceReflow) { el.offsetWidth; } el.style.transition = "transform .5s"; el.style.transform = ""; } document.querySelector("button").onclick = move;
.elem { width: 100px; height: 100px; border: 1px solid grey; } .parent { display: flex; padding: 3rem; }