概述
在使用elementplus文档的时候,如果留意的话,点击主题切换,会发现有一个鱼眼动画的奇幻,非常的炫酷如下:

实现效果
咱也实现一个差不多的
实现
ViewTransition API
实现上面的效果,先介绍下,ViewTransition,View Transitions API 的 ViewTransition
接口表示视图过渡,并提供了在过渡到达不同状态时运行代码的功能(例如,准备运行动画,或动画完成),或跳过视图过渡。(mdn解释),View Transitions API 简化了复杂动画的实现,无需手动处理位置计算或动画控制,适合页面级的场景切换和动画增强。
具体代码事先
主要涉及到我们需要通过api提供的接口去做动画处理。
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
:root {
--color: #fff;
background-color: var(--color);
}
:root.dark {
--color: #008c8c;
}
::view-transition-new(root),
::view-transition-old(root) {
animation: none;
}
.dark::view-transition-old(root) {
z-index: 100;
}
</style>
</head>
<body>
<button id="operate-btn">切换主题</button>
<script>
const operateBtn = document.getElementById('operate-btn');
function toggleTheme() {
document.documentElement.classList.toggle('dark');
}
function operateFn(e) {
const transition = document.startViewTransition(() => {
toggleTheme()
});
transition.ready.then(() => {
const { clientX, clientY } = e;
// 计算半径,以鼠标点击的位置为圆心,到四个角的距离中最大的那个作为半径
const radius = Math.hypot(
Math.max(clientX, innerWidth - clientX),
Math.max(clientY, innerHeight - clientY)
);
const clipPath = [
`circle(0% at ${clientX}px ${clientY}px)`,
`circle(${radius}px at ${clientX}px ${clientY}px)`
];
const isDark = document.documentElement.classList.contains('dark');
const clipPathList = isDark ? clipPath.reverse() : clipPath
document.documentElement.animate(
{
// 切换方向相反
clipPath: clipPathList
},
{
duration: 300,
// 如果要切换到暗色主题
pseudoElement: isDark
? '::view-transition-old(root)'
: '::view-transition-new(root)'
}
);
});
}
operateBtn.addEventListener('click', operateFn);
</script>
</body>
</html>