实现一个丝滑的暗黑模式切换动画
参考内容:
参考文章:https://juejin.cn/post/7269388083342082107
MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/View_Transitions_API https://developer.mozilla.org/zh-CN/docs/Web/CSS/::view-transition-new
实现方式就是利用vueuse将html元素动态添加class类名dark
利用伪元素::view-transition-old
以及::view-transition-new
,如需了解这两个伪元素,请移步文章开头参考内容
可以这样理解,调用document.startViewTransition(() => { /* 修改html元素类名 */ })
方法时,在该方法的回调函数中,添加修改页面变化的代码;
这样伪元素::view-transition-old
记录的就是修改之前的页面'截图',而伪元素::view-transition-new
是修改页面变化后的页面,然后是这两个伪元素进行的动画过渡
如果你想快速在项目中添加该动画,请添加以下代码
*css
html {
--g-tabbar-border: #c9c9c9;
--g-tabbar-item-after: #595959;
--g-about-link-border: #c9c9c9;
--g-about-link-hover: #374151;
--g-blog-bg-color: #d4d4d4;
}
html.dark {
--g-tabbar-border: #595959;
--g-tabbar-item-after: #fff;
--g-about-link-border: #374151;
--g-about-link-hover: #fff;
--g-blog-bg-color: #8a8a8a;
}
::view-transition-old(*) {
animation: none;
}
::view-transition-new(*) {
animation: clip .5s ease-in;
}
::view-transition-old(root) {
z-index: 1;
}
::view-transition-new(root) {
z-index: 9999;
}
html.dark::view-transition-old(*) {
animation: clip .5s ease-in reverse;
}
html.dark::view-transition-new(*) {
animation: none;
}
html.dark::view-transition-old(root) {
z-index: 9999;
}
html.dark::view-transition-new(root) {
z-index: 1;
}
@keyframes clip {
from {
clip-path: circle(0% at var(--x) var(--y));
}
to{
clip-path: circle(var(--r) at var(--x) var(--y));
}
}
clip-path
css样式中的 circle
函数,第一个参数就是圆的半径,第二、三个参数是圆心坐标
*js
const changeBtn = (func, $eve) => {
const x = $eve.clientX
const y = $eve.clientY
// 计算鼠标点击位置距离视窗的最大圆半径
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y),
)
document.documentElement.style.setProperty('--x', x + 'px')
document.documentElement.style.setProperty('--y', y + 'px')
document.documentElement.style.setProperty('--r', endRadius + 'px')
// 判断浏览器是否支持document.startViewTransition
if (document.startViewTransition) {
// 如果支持就使用document.startViewTransition方法
document.startViewTransition(() => {
func.call() // 这里的函数是切换主题的函数,调用changeBtn函数时进行传入
})
} else {
// 如果不支持,就使用最原始的方式,切换主题
func.call()
}
}
动画会用到鼠标点击按钮时的点击坐标
如果你想快速测试,在添加css代码后,直接在浏览器控制台Console中运行以下代码测试
*测试
document.querySelector('html').setAttribute('style', '--r: 100px; --x: 100px; --y: 100px;')
document.startViewTransition(() => {
document.querySelector('html').classList.toggle('dark')
})
完整案例
<!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>
html {
--bg-color: #000;
--text-color: #fff;
}
html.dark {
--bg-color: #fff;
--text-color: #000;
}
::view-transition-old(*) {
animation: none;
}
::view-transition-new(*) {
animation: clip 0.5s ease-in;
}
::view-transition-old(root) {
z-index: 1;
}
::view-transition-new(root) {
z-index: 9999;
}
html.dark::view-transition-old(*) {
animation: clip 0.5s ease-in reverse;
}
html.dark::view-transition-new(*) {
animation: none;
}
html.dark::view-transition-old(root) {
z-index: 9999;
}
html.dark::view-transition-new(root) {
z-index: 1;
}
@keyframes clip {
from {
clip-path: circle(0% at var(--x) var(--y));
}
to {
clip-path: circle(var(--r) at var(--x) var(--y));
}
}
/* 样式写法例子,使用css变量,可以实现动态切换主题 */
body {
background-color: var(--bg-color);
color: var(--text-color);
}
</style>
</head>
<body>
<h1>
test text
</h1>
<button id="btn">changeTheme</button>
<script>
// 主题切换函数
const changeTheme = () => {
document.querySelector('html').classList.toggle('dark')
}
const changeBtn = (func, $eve) => {
const x = $eve.clientX
const y = $eve.clientY
// 计算鼠标点击位置距离视窗的最大圆半径
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y),
)
document.documentElement.style.setProperty('--x', x + 'px')
document.documentElement.style.setProperty('--y', y + 'px')
document.documentElement.style.setProperty('--r', endRadius + 'px')
// 判断浏览器是否支持document.startViewTransition
if (document.startViewTransition) {
// 如果支持就使用document.startViewTransition方法
document.startViewTransition(() => {
func.call() // 这里的函数是切换主题的函数,调用changeBtn函数时进行传入
})
} else {
// 如果不支持,就使用最原始的方式,切换主题
func.call()
}
}
document.getElementById('btn').addEventListener('click', (e) => {
changeBtn(changeTheme, e)
})
</script>
</body>
</html>
转载本文无需作者授权,但一定要标明为转载内容,并标明转载博客地址:https://www.cnblogs.com/ganto/articles/17941426