FLIP是 First、Last、Invert和 Play四个单词首字母的缩写
- first: 保留变化前的状态
- last: 记录变化后的状态
- invent: 通过first和last计算,还原到first状态
- play: 执行动画,实现first到last的转变
图片翻转
import "web-animations-js"
import React, { useState, useEffect, useLayoutEffect, useRef } from "react";
import styled from "styled-components";
const Container = styled.div`
display: flex;
flex-wrap: wrap;
column-count: 4;
margin: auto;
width: 800px;
`;
const ImgWrap = styled.div`
width: 25%;
padding: 8px;
box-sizing: border-box;
`;
const Img = styled.img`
width: 100%;
height: 200px;
border-radius: 8px;
object-fit: cover;
`;
export default function () {
// 根节点
const root = useRef();
// 保留前一个状态
const prev = useRef(null);
const [imgs, setImgs] = useState([
"https://pic3.zhimg.com/v2-89735fee10045d51693f1f74369aaa46_r.jpg",
"https://pic1.zhimg.com/v2-ca51a8ce18f507b2502c4d495a217fa0_r.jpg",
"https://pic1.zhimg.com/v2-c90799771ed8469608f326698113e34c_r.jpg",
"https://pic1.zhimg.com/v2-8d3dd83f3a419964687a028de653f8d8_r.jpg",
"https://pic1.zhimg.com/v2-09eefac19ac282684f60a202aa9abb2c_r.jpg",
"https://pic3.zhimg.com/v2-a7340ebca1f7a4f65190583b4ab3a482_r.jpg",
"https://pic2.zhimg.com/v2-37860484a1a73257178e95267c7db641_r.jpg",
"https://pic2.zhimg.com/v2-7fc30291c807d07d2d26c5a8ffdd3b89_r.jpg",
]);
useLayoutEffect(() => {
if (prev.current === null) {
// mounted保留前状态
prev.current = Array.from(root.current.children).map((dom) => {
const rect = dom.getBoundingClientRect();
return { dom, pos: { left: rect.left, top: rect.top } };
});
} else {
prev.current.map(({ dom, pos }) => {
// 获取新状态
const rect = dom.getBoundingClientRect();
// invent 还原到初始状态
dom.style = `transform: translate(${pos.left - rect.left}px, ${
pos.top - rect.top
}px)`;
// play: 执行动画
dom.animate(
[
{
transform: `translate(${pos.left - rect.left}px, ${
pos.top - rect.top
}px)`,
},
{
transform: "translate(0,0)",
},
],
{
duration: 300,
easing: "cubic-bezier(0,0,0.32,1)",
fill: "forwards",
}
);
});
// 保存前状态
prev.current = Array.from(root.current.children).map((dom) => {
const rect = dom.getBoundingClientRect();
return { dom, pos: { left: rect.left, top: rect.top } };
});
}
}, [imgs]);
return (
<Container ref={root}>
{imgs.map((img) => (
<ImgWrap
key={img}
onClick={() => {
// 将数组打乱
setImgs((imgs) => [
...imgs.sort(() => (Math.random() > 0.5 ? -1 : 1)),
]);
}}
>
<Img src={img} />
</ImgWrap>
))}
</Container>
);
}