主题切换过渡切割效果
- 效果图
- 上代码
效果图
参考api View Transitions API
View Transitions API 提供了一种机制,可以在更新 DOM 内容的同时,轻松地创建不同 DOM 状态之间的动画过渡。同时还可以在单个步骤中更新 DOM 内容。
上代码
<!--
* @Descripttion:
* @Author: 苍狼一啸八荒惊
* @Date: 2024-09-03 14:16:43
* @LastEditTime: 2024-09-04 14:06:25
* @LastEditors: 夜空孤狼啸
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>主题切换</title>
<style>
:root {
/* 亮色模式下的背景色 */
--bg-color: #fff;
--text-color: #232324;
background-color: var(--bg-color);
}
:root.dark {
/* 暗色模式下的背景色 */
--text-color: #dbdbdf;
--bg-color: #000;
}
.dark::view-transition-old(root) {
z-index: 100;
}
::view-transition-new(root),
::view-transition-old(root) {
/* 关闭默认动画,否则影响自定义动画的执行 */
animation: none;
}
body {
color: var(--text-color);
}
</style>
</head>
<body>
<button id="btn">切换主题</button>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<h1>点击按钮时切换主题</h1>
<script>
const btn = document.getElementById('btn')
// 点击按钮时切换主题
btn.addEventListener('click', (e) => {
// 获取到 transition API 实例
const transition = document.startViewTransition(() => {
document.documentElement.classList.toggle('dark')
})
// 在 transition.ready 的 Promise 完成后,执行自定义动画
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')
console.log(isDark)
// 自定义动画
document.documentElement.animate(
{
// 如果要切换到暗色主题,我们在过渡的时候从半径 100% 的圆开始,到 0% 的圆结束
clipPath: isDark ? clipPath.reverse() : clipPath
},
{
duration: 500,
// 如果要切换到暗色主题,我们应该裁剪 view-transition-old(root) 的内容
pseudoElement: isDark
? '::view-transition-old(root)'
: '::view-transition-new(root)'
}
)
})
})
</script>
</body>
</html>