Flip技术
前言
在我们使用vue
做一些卡片移动效果的动画时候,可能会想到使用transition
来实现,这样就不会显得生硬,但是在一些项目里面需要去操作样式,这时针对css
的transition
可能做起来会很困难,改变的不是css
,而是元素的结构,这时候就很困难了
了解Flip
Flip是 First
、Last
、Invert
和 Play
四个单词首字母的缩写
字面意思:
First:这也是我们首先做的,这里我们需要使用
getBoundingClientRect()
这个API
来处理(offsetLeft
和offsetTop
也是可以的),这里主要是记录我们元素出现的位置使用一个值来记录,方便后续改变之后的值现成对比Last:代码执行完毕之后,让元素发生相应的变化,并记录元素在动画最后状态的位置和尺寸,即动画结束之后那一刻收集元素的位置和尺寸信息
Invert:有着转化的意思,这一步简单的概括就是将开始和结束的位置进行标记对比,计算好差值,然后使用
transform
属性将元素反转回动画的开始状态,这一时刻js已经计算好了等待Play的执行Play:这一步简单理解为将计算好的
transform
应用起来,这时候这个动画形式就运行起来了
通俗的来讲就是,开始记录一次初始位置,再记录结束位置,计算好初识和结束的偏差值,应用执行transform
示例
用一个简单的封装示例就可以演示出动画
新建好index.html
,书写以下内容:
<!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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.btn {
margin: 50px auto 10px;
width: 100px;
text-align: center;
}
.btn button {
margin: 0 1em;
outline: none;
border: none;
background: #579ef8;
color: #fff;
padding: 7px 10px;
border-radius: 5px;
cursor: pointer;
}
.container {
width: 500px;
margin: 20px auto;
display: flex;
justify-content: space-around;
align-items: center;
padding: 30px;
box-sizing: border-box;
background-color: #eee;
}
.text {
width: 50px;
height: 50px;
background-color: yellowgreen;
line-height: 50px;
text-align: center;
}
</style>
</head>
<body>
<div class="btn">
<button>排序</button>
</div>
<div class="container">
<div class="text">老大</div>
<div class="text">老二</div>
<div class="text">老三</div>
<div class="text">老四</div>
<div class="text">老五</div>
<div class="text">老六</div>
<div class="text">老七</div>
</div>
<script>
let container = document.querySelector('.container');
let btn = document.querySelector('.btn');
btn.onclick = () => {
record(container)
let length = container.children.length;
let index = 0
// if (index < length - 1) { 这个就是逐个执行,点击按钮执行一次
while (index < length - 1) { // 一次性执行完毕,点击按钮直接反转
let node = container.children[index]
let lastNode = container.children[length - 1]
container.insertBefore(lastNode, node)
index++
}
move(container)
}
function record(container) {
for (let i = 0, len = container.children.length; i < len; i++) {
const dom = container.children[i]
const rect = dom.getBoundingClientRect()
dom.startX = rect.left
dom.startY = rect.top
}
}
function move(container) {
for (let i = 0, len = container.children.length; i < len; i++) {
const dom = container.children[i]
const rect = dom.getBoundingClientRect()
const curX = rect.left, curY = rect.top
dom.animate([
{ transform: `translate(${dom.startX - curX}px, ${dom.startY - curY}px)` },
{ transform: `translate(0px, 0px)` }
], { duration: 600 })
}
}
</script>
</body>
</html>
record
函数记录好初始的位置
move
函数记录好结束的位置,并计算好初始和结束的差值并应用上去。