FLIP是什么
鹿酒 2022/1/22 CSSJavaScript
# 概念
FLIP是一种可以高效为元素位置、尺寸做动画的技术。
F:First 元素的初始状态
L:Last 元素最终的形态
I:Invert 反转,意思是动画的过程本来是从A到B,现在理解为当前位置是B,上个位置是A
P:Play 播放
Vue中的动画的实现原理就是这个 传送门 (opens new window)
# 实现
.square{height: 120px;width: 120px; position: fixed; top: 100px; left: 100px;background-color: silver;}
.position1{height: 180px;width: 90px;top: 200px; left: 170px;}
1
2
2
function move(dom){
dom.classList.add('position1')
}
const square = document.querySelector('.square')
const first = square.getBoundingClientRect();
move(square); // 执行位置变换的脚本
const last = square.getBoundingClientRect();
console.log(first, last); // 方法返回元素的大小及其相对于视口的位置。
const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
const deltaW = first.width / last.width;
const deltaH = first.height / last.height;
console.log(deltaX, deltaY, deltaW, deltaH);
const frames = {
transformOrigin: ['top left', 'top left'],
transform: [`translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`, 'none'] // 计算初始帧和结束帧
}
const options = {
duration: 300,
easing: 'ease-in-out',
fill: 'both'
}
// Element API: animate(关键帧集合, 动画选项)
// square.animate(frames, options); // 兼容很差: IE、Edge<79、Chrome<59、safari<8、移动端UC、QQ、Baidu不支持
// Element API: animate polyfill
square.animate(frames, options);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 拓展例子
点击页面,方块进入,再次点击,方块位置大小来回切换。
实际生产中 可以在弹窗中使用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FLIP</title>
<style>
.square{position: fixed;background-color: silver;} /* 初始帧 */
.frameIn{height: 180px;width: 90px;top: 200px; left: 170px;}
.frameOut{height: 280px;width: 190px;top: 80px; left: 320px;}
</style>
</head>
<body>
<div class="square"></div>
<script>
function slibingsFrame(dom, classIn, classOut){
const options = {
duration: 300,
easing: 'ease-in-out',
fill: 'both'
}
const first = square.getBoundingClientRect();
let isIn = false
if(dom.classList.value.includes(classIn)){
dom.classList.remove(classIn)
dom.classList.add(classOut)
isIn = false
}else{
dom.classList.add(classIn)
dom.classList.remove(classOut)
isIn = true
}
const last = square.getBoundingClientRect();
const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
const deltaW = first.width / last.width;
const deltaH = first.height / last.height;
const framesTo = {
transformOrigin: ['top left', 'top left'],
transform: [`translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`, 'none']
}
dom.animate(framesTo, options)
}
const square = document.querySelector('.square')
document.onclick = function(){
slibingsFrame(square, 'frameIn', 'frameOut')
}
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 总结
推荐阅读
FLIP作者的 FLIP your animations (opens new window)