聚焦式切换主题模式-light/dark
知识点罗列
效果示例
<script lang='ts' setup>
import { nextTick, ref, watch } from 'vue'
import { ElSwitch } from 'element-plus'
import { isDark, toggleDark } from './dark'
const darkMode = ref(isDark.value)
watch(
() => darkMode.value,
() => {
console.log('change-------mode')
toggleDark()
},
)
let resolveFn: (value: boolean | PromiseLike<boolean>) => void
function switchTheme(event: MouseEvent) {
console.log('change-------start')
const isAppearanceTransition
// @ts-expect-error
= document.startViewTransition
&& !window.matchMedia('(prefers-reduced-motion: reduce)').matches
if (!isAppearanceTransition || !event) {
resolveFn(true)
return
}
const x = event.clientX
const y = event.clientY
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y),
)
// @ts-expect-error: Transition API
const transition = document.startViewTransition(async () => {
resolveFn(true)
await nextTick()
})
transition.ready.then(() => {
console.log('change-------transition')
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,
]
document.documentElement.animate(
{
clipPath: isDark.value ? [...clipPath].reverse() : clipPath,
},
{
duration: 500,
easing: 'ease-in',
pseudoElement: isDark.value
? '::view-transition-old(root)'
: '::view-transition-new(root)',
},
)
})
}
function beforeChange(): Promise<boolean> {
return new Promise((resolve) => {
resolveFn = resolve
})
}
</script>
<template>
<div class="custom-wrapper" @click.stop="switchTheme">
<ClientOnly>
<ElSwitch
v-model="darkMode"
:before-change="beforeChange"
active-text="Dark"
inactive-text="Light"
/>
</ClientOnly>
</div>
</template>
<style lang='scss' scoped>
</style>
知识点介绍以及使用
View Transition是谷歌浏览器提供的一个新特性,也叫做视图转换动画,或者转场动画能有平滑有效的实现动画的切换效果。
::view-transition表示视图过渡层叠层的根元素,他的结构大概有四层,它包含所有视图过渡且位于所有其他页面内容的顶部,也就是说他的相对父级是HTML元素
在视图过渡期间,::view-transition 包含在相关的伪元素树中,它是该树的顶级节点,并且有一个或多个 ::view-transition-group 子节点。
以上视图切换过程仅用于了解其运作原理,核心在于一行JS代码,---> document.startViewTransition,该函数用于启动视图转换
整体过程如下:
- 调用document.startViewTransition浏览器会捕捉当前页面的状态以及画面
- 执行dom变化,之后会再次记录变化后的页面状态,也是类似于捕获画面
- 触发两个状态之间的过度,例如颜色、宽高、背景、位移等变化,也可以是animation动画
该过程可以通过document.documentElement.animate函数触发、更改class、启用animation等
null