为实现element-plus主题切换这样一个动画效果,我们可以使用到web api提供的一个
View Transitions API
mdn上官方的详细介绍 https://developer.mozilla.org/zh-CN/docs/Web/API/View_Transitions_API
View Transitions API 提供了一种机制,可以在更新 DOM 内容的同时,轻松地创建不同 DOM 状态之间的动画过渡。同时还可以在单个步骤中更新 DOM 内容。
其中最主要的操作由Document:startViewTransition() 方法提供
现在来看看具体的实现效果
1、首先在页面中定义好基本的结构
<style>
:root {
--theme-color: #000;
--bg-color: #fff;
background-color: var(--bg-color);
color: var(--theme-color);
}
:root.dark {
--bg-color: #303030;
--theme-color: #fff;
}
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
} // 清除切换的默认动画,否则自定义的切换动画会不生效
</style>
<body>
<button class="btn">切换背景颜色</button>
</body>
2、添加js事件
const btn = document.querySelector(".btn");
btn.addEventListener("click", (e) => {
let transition = document.startViewTransition(() => {
document.documentElement.classList.toggle("dark");
}); // 监听按钮的点击事件,并使用 startViewTransition 事件 得到一个 transition
transition.ready.then(() => {
// 获取选中元素的位置信息
const x = e.clientX;
const y = e.clientY;
// 获取画圆的半径
const radius = Math.sqrt(
Math.max(x, window.innerWidth - x) ** 2 +
Math.max(y, window.innerHeight - y) ** 2
); // 勾股定理
document.documentElement.animate(
{
clipPath: [
`circle(0 at ${x}px ${y}px)`,
`circle(${radius}px at ${x}px ${y}px)`,
],
}, // 在坐标x,y处从半径为0的圆变为半径为radius的圆
{
duration: 800,
// 指定要附加动画的伪元素
pseudoElement: "::view-transition-new(root)",
}
);
});
});
3、完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
:root {
--theme-color: #000;
--bg-color: #fff;
background-color: var(--bg-color);
color: var(--theme-color);
}
:root.dark {
--bg-color: #303030;
--theme-color: #fff;
}
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
}
</style>
</head>
<body>
<button class="btn">切换背景颜色</button>
<div class="content">
<p>内容1</p>
<p>内容2</p>
<p>内容3</p>
<p>内容4</p>
<p>内容5</p>
</div>
</body>
<script>
const btn = document.querySelector(".btn");
btn.addEventListener("click", (e) => {
let transition = document.startViewTransition(() => {
document.documentElement.classList.toggle("dark");
});
transition.ready.then(() => {
// 获取选中元素的位置信息
const x = e.clientX;
const y = e.clientY;
// 获取画圆的半径
const radius = Math.sqrt(
Math.max(x, window.innerWidth - x) ** 2 +
Math.max(y, window.innerHeight - y) ** 2
); // 勾股定理
document.documentElement.animate(
{
clipPath: [
`circle(0 at ${x}px ${y}px)`,
`circle(${radius}px at ${x}px ${y}px)`,
],
}, // 在坐标x,y处从半径为0的圆变为半径为radius的圆
{
duration: 800,
pseudoElement: "::view-transition-new(root)",
}
);
});
});
</script>
</html>