背景特效切换美化

This commit is contained in:
2025-12-07 21:31:31 +08:00
parent 6e4cdd22f9
commit 89d2330e72
4 changed files with 79 additions and 7 deletions
+70 -1
View File
@@ -112,7 +112,12 @@ function switchView(view: 'editor' | 'manager' | 'presets') {
currentView.value = view currentView.value = view
} }
function cycleBackground() { function cycleBackground(event?: MouseEvent) {
const isAppearanceTransition = 'startViewTransition' in document
&& !window.matchMedia('(prefers-reduced-motion: reduce)').matches
&& event instanceof MouseEvent
const updateState = () => {
const currentIndex = bgModes.indexOf(currentBgMode.value) const currentIndex = bgModes.indexOf(currentBgMode.value)
const nextIndex = (currentIndex + 1) % bgModes.length const nextIndex = (currentIndex + 1) % bgModes.length
const nextMode = bgModes[nextIndex] const nextMode = bgModes[nextIndex]
@@ -120,6 +125,70 @@ function cycleBackground() {
currentBgMode.value = nextMode currentBgMode.value = nextMode
localStorage.setItem('bg.mode', currentBgMode.value) localStorage.setItem('bg.mode', currentBgMode.value)
} }
}
if (!isAppearanceTransition) {
updateState()
return
}
const x = event.clientX
const y = event.clientY
const transition = document.startViewTransition(async () => {
updateState()
await nextTick()
})
transition.ready.then(() => {
const effects = ['circle', 'vertical', 'horizontal', 'diamond']
const effect = effects[Math.floor(Math.random() * effects.length)]
let clipPath: string[] = []
if (effect === 'circle') {
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
)
clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`
]
} else if (effect === 'vertical') {
clipPath = [
'inset(0 0 100% 0)',
'inset(0 0 0 0)'
]
} else if (effect === 'horizontal') {
clipPath = [
'inset(0 100% 0 0)',
'inset(0 0 0 0)'
]
} else if (effect === 'diamond') {
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
) * 1.5 // Multiply to ensure coverage for diamond shape
clipPath = [
`polygon(${x}px ${y}px, ${x}px ${y}px, ${x}px ${y}px, ${x}px ${y}px)`,
`polygon(${x}px ${y - endRadius}px, ${x + endRadius}px ${y}px, ${x}px ${y + endRadius}px, ${x - endRadius}px ${y}px)`
]
}
document.documentElement.animate(
{
clipPath: clipPath,
},
{
duration: 1500,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
pseudoElement: '::view-transition-new(root)',
fill: 'forwards',
}
)
})
} }
const bgModeLabel = computed(() => { const bgModeLabel = computed(() => {
@@ -168,6 +168,7 @@ onMounted(() => {
}) })
window.addEventListener('mousemove', onMouseMove, { passive: true }) window.addEventListener('mousemove', onMouseMove, { passive: true })
document.addEventListener('visibilitychange', onVisibilityChange) document.addEventListener('visibilitychange', onVisibilityChange)
draw() // Initial draw to ensure no flicker
raf = requestAnimationFrame(loop) raf = requestAnimationFrame(loop)
}) })
@@ -185,6 +185,7 @@ onMounted(() => {
initMesh() initMesh()
window.addEventListener('resize', onResize) window.addEventListener('resize', onResize)
window.addEventListener('mousemove', onMouseMove) window.addEventListener('mousemove', onMouseMove)
draw() // Initial draw
raf = requestAnimationFrame(loop) raf = requestAnimationFrame(loop)
}) })
@@ -132,6 +132,7 @@ onMounted(() => {
resize() resize()
window.addEventListener('resize', resize) window.addEventListener('resize', resize)
window.addEventListener('mousemove', onMouseMove) window.addEventListener('mousemove', onMouseMove)
draw() // Initial draw
raf = requestAnimationFrame(loop) raf = requestAnimationFrame(loop)
}) })