[vue] vue3封装clip动画, 实现元素的国度效果
import { nextTick } from "vue";
// 数据类型
function getDataType() {
return Object.prototype.toString.call(arguments[0]).slice(8, -1).toLowerCase();
}
/**
*
* @param {*} els 单元素节点 或者 元素节点集合
* @param {*} fn 数据变更的函数,通过调用函数导致外部数据变更
* @param {*} duration 动画执行时间,默认500ms
*/
export default function (els, fn, duration = 500) {
// 整合成数组格式
let originList = [];
if (getDataType(els) === "htmlcollection") {
originList = [...els]
} else {
originList = [els]
}
// 生成原始位置
const originPositions = [];
originList.forEach(el => {
const info = el.getBoundingClientRect()
originPositions.push({
top: info.top,
left: info.left,
width: info.width,
height: info.height,
bottom: info.bottom,
right: info.right,
x: info.x,
y: info.y,
})
})
// 执行函数
fn && fn()
nextTick(() => {
// 页面更新后获取最新位置
const newPositions = [];
originList.forEach(el => {
const info = el.getBoundingClientRect()
newPositions.push({
top: info.top,
left: info.left,
width: info.width,
height: info.height,
bottom: info.bottom,
right: info.right,
x: info.x,
y: info.y,
})
})
// 计算移动距离
const movePositions = [];
originPositions.forEach((origin, index) => {
const newPosition = newPositions[index]
const moveX = newPosition.left - origin.left
const moveY = newPosition.top - origin.top
const newWidth = newPosition.width
const newHeight = newPosition.height
movePositions.push({
moveX,
moveY,
newWidth,
newHeight,
})
})
// 做动画
originList.forEach((el, index) => {
const moveX = movePositions[index].moveX
const moveY = movePositions[index].moveY
el.animate([
{
transform: `translate(${-moveX}px, ${-moveY}px)`,
width: `${originPositions[index].width}px`,
height: `${originPositions[index].height}px`,
},
{
transform: `translate(0, 0)`,
width: `${movePositions[index].newWidth}px`,
height: `${movePositions[index].newHeight}px`,
}
], duration)
})
})
}
解释: js也能做相当于css的动画, 用元素的animate方法
css的写法等同于用js操作dom的css
el.animate([
{css},
{css}
])
核心原理是: 知道元素移动的终点位置(endx,endy), 和元素的起点位置 (startx, starty)
假设: 我们现在处于元素 最终 所在的位置 (endx,endy), 然后通过transform...等手段, 将元素变更到 (startx, starty)位置 (这时候和没移动之前的位置是一样的)
然后通过animate执行动画, 位置就从 (startx, starty) `还原` 到 (endx, endy), 形成动画
在用户看来, 元素是从起点慢慢移动到终点的, 对于程序而言, 元素立即就移动到了终点, 通过 css 变化位置到了起点,慢慢还原
vue的nextTick提供了很好的 虚拟dom支持, 在界面没有渲染之前, 我么就能通过虚拟dom拿到元素变更后的位置信息, 更容易和 animate 结合使用
如果是原生html想做clip动画, 就需要通过其他方法计算提前计算出终点的位置, 然后运用动画
本想把生活活成一首诗, 时而优雅 , 时而豪放 , 结果活成了一首歌 , 时而不靠谱 , 时而不着调

浙公网安备 33010602011771号