mirror of
				https://gitee.com/SuperManito/LinuxMirrors
				synced 2025-11-04 16:30:26 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			91 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
function useThemeTransition() {
 | 
						||
    // 更新过渡样式变量
 | 
						||
    function updateViewTransitionVariables(isDarkTheme) {
 | 
						||
        document.documentElement.style.setProperty('--view-transition-z-index-foreground', isDarkTheme ? '999' : '1')
 | 
						||
        document.documentElement.style.setProperty('--view-transition-z-index-background', isDarkTheme ? '1' : '999')
 | 
						||
    }
 | 
						||
    // 切换主题按钮点击事件
 | 
						||
    function handleThemeToggle(e) {
 | 
						||
        // 阻止默认点击事件
 | 
						||
        e.preventDefault()
 | 
						||
        e.stopPropagation()
 | 
						||
        // 获取目标输入元素
 | 
						||
        const targetId = this.getAttribute('for')
 | 
						||
        const targetInput = document.getElementById(targetId)
 | 
						||
        if (!targetInput) return
 | 
						||
        // 获取主题状态
 | 
						||
        const targetTheme = targetInput.getAttribute('data-md-color-scheme') // 目标主题(system、default、slate)
 | 
						||
        const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'slate' : 'default' // 系统主题(default、slate)
 | 
						||
        const currentScheme = document.body.getAttribute('data-md-color-scheme') // 当前主题(default、slate)
 | 
						||
        // 当目标主题与当前主题相同时不触发动画
 | 
						||
        if (targetTheme === 'system') {
 | 
						||
            if (systemTheme === currentScheme) {
 | 
						||
                targetInput.click()
 | 
						||
                return
 | 
						||
            }
 | 
						||
        } else if (targetTheme === currentScheme) {
 | 
						||
            targetInput.click()
 | 
						||
            return
 | 
						||
        }
 | 
						||
        // 当前主题状态
 | 
						||
        const isSystemDarkTheme = systemTheme === 'slate' // 系统是否为深色主题
 | 
						||
        const isCurrentDarkTheme = currentScheme.includes('slate') // 当前是否为深色主题
 | 
						||
        const isSwitchToDarkTheme = !isCurrentDarkTheme // 是否将切换到深色主题
 | 
						||
        // 根据系统主题设置动画样式
 | 
						||
        updateViewTransitionVariables(isSystemDarkTheme)
 | 
						||
        // 判断切换方向是否与系统主题一致
 | 
						||
        // 如果系统是深色,切换到深色是"靠近系统";如果系统是浅色,切换到浅色是"靠近系统"
 | 
						||
        const isMovingTowardsSystemTheme = (isSwitchToDarkTheme && isSystemDarkTheme) || (!isSwitchToDarkTheme && !isSystemDarkTheme)
 | 
						||
        // 动画参数
 | 
						||
        const x = e.clientX
 | 
						||
        const y = e.clientY
 | 
						||
        const endRadius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y))
 | 
						||
        const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]
 | 
						||
        // 启动视图过渡
 | 
						||
        document
 | 
						||
            .startViewTransition(async () => {
 | 
						||
                // 切换主题
 | 
						||
                targetInput.click()
 | 
						||
                // 添加CSS类用于动画控制
 | 
						||
                document.documentElement.classList.remove(isSwitchToDarkTheme ? 'light' : 'dark')
 | 
						||
                document.documentElement.classList.add(isSwitchToDarkTheme ? 'dark' : 'light')
 | 
						||
                // 等待主题变化完成
 | 
						||
                await new Promise((resolve) => setTimeout(resolve, 100))
 | 
						||
            })
 | 
						||
            .ready.then(() => {
 | 
						||
                // 当朝向系统主题方向变化时使用使用缩小效果(reversed clipPath),反之放大效果(clipPath)
 | 
						||
                document.documentElement.animate(
 | 
						||
                    {
 | 
						||
                        clipPath: isMovingTowardsSystemTheme ? [...clipPath].reverse() : clipPath,
 | 
						||
                        transform: 'translateZ(0)',
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        duration: 500,
 | 
						||
                        easing: 'ease-in',
 | 
						||
                        pseudoElement: isMovingTowardsSystemTheme ? '::view-transition-old(root)' : '::view-transition-new(root)',
 | 
						||
                    }
 | 
						||
                )
 | 
						||
            })
 | 
						||
    }
 | 
						||
 | 
						||
    // 不支持此特性
 | 
						||
    if (typeof document.startViewTransition !== 'function') {
 | 
						||
        return
 | 
						||
    }
 | 
						||
    // 获取主题切换按钮Dom
 | 
						||
    const themeToggles = document.querySelectorAll('form[data-md-component="palette"] .md-header__button.md-icon')
 | 
						||
    themeToggles.forEach((toggle) => {
 | 
						||
        toggle.addEventListener('click', handleThemeToggle, { capture: true })
 | 
						||
    })
 | 
						||
    // 初始化主题状态类
 | 
						||
    const currentScheme = document.body.getAttribute('data-md-color-scheme')
 | 
						||
    const isDark = currentScheme.includes('slate')
 | 
						||
    document.documentElement.classList.add(isDark ? 'dark' : 'light')
 | 
						||
    // 初始化过渡样式变量
 | 
						||
    updateViewTransitionVariables(isDark)
 | 
						||
}
 | 
						||
 | 
						||
document.addEventListener('DOMContentLoaded', function () {
 | 
						||
    useThemeTransition()
 | 
						||
})
 |