index.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <template>
  2. <el-switch
  3. v-if="'technology' != theme.themeName && 'plain' != theme.themeName"
  4. v-model="mode"
  5. :active-icon="Moon"
  6. active-value="dark"
  7. class="vab-dark"
  8. :inactive-icon="Sunny"
  9. inactive-value="light"
  10. inline-prompt
  11. @click="_toggleDark($event)"
  12. />
  13. </template>
  14. <script lang="ts" setup>
  15. // @ts-nocheck
  16. import { Moon, Sunny } from '@element-plus/icons-vue'
  17. import { useSettingsStore } from '/@/store/modules/settings'
  18. defineOptions({
  19. name: 'VabDark',
  20. })
  21. const $sub = inject<any>('$sub')
  22. const $unsub = inject<any>('$unsub')
  23. const settingsStore = useSettingsStore()
  24. const { theme, mode } = storeToRefs(settingsStore)
  25. const { updateMode } = settingsStore
  26. const _toggleDark = async (event: MouseEvent) => {
  27. if (typeof document.startViewTransition === 'function') {
  28. const x = event.clientX
  29. const y = event.clientY
  30. const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y))
  31. let isDark: boolean
  32. const transition = document.startViewTransition(() => {
  33. const root = document.documentElement
  34. isDark = root.classList.contains('dark')
  35. root.classList.remove(isDark ? 'dark' : 'light')
  36. root.classList.add(isDark ? 'light' : 'dark')
  37. handleSetScheme(isDark ? 'light' : 'dark')
  38. })
  39. await transition.ready.then(() => {
  40. const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]
  41. document.documentElement.animate(
  42. {
  43. clipPath: isDark ? [...clipPath].reverse() : clipPath,
  44. },
  45. {
  46. duration: 500,
  47. easing: 'ease-in',
  48. pseudoElement: isDark ? '::view-transition-old(root)' : '::view-transition-new(root)',
  49. }
  50. )
  51. })
  52. } else {
  53. const toggleDark = useToggle(handleUseDark())
  54. await toggleDark()
  55. }
  56. await updateMode(localStorage.getItem('vueuse-color-scheme'))
  57. }
  58. const handleUseDark = () => {
  59. return useDark()
  60. }
  61. const handleGetScheme = () => {
  62. return localStorage.getItem('vueuse-color-scheme')
  63. }
  64. const handleSetScheme = (value: string) => {
  65. return localStorage.setItem('vueuse-color-scheme', value)
  66. }
  67. // 还原默认
  68. $sub('shop-vite-reset-dark', () => {
  69. mode.value = handleGetScheme()
  70. if (handleGetScheme() === 'dark') {
  71. handleSetScheme('light')
  72. handleUseDark()
  73. mode.value = 'light'
  74. }
  75. })
  76. onBeforeMount(() => {
  77. handleUseDark()
  78. if (handleGetScheme() === 'auto') handleSetScheme('light')
  79. mode.value = handleGetScheme()
  80. })
  81. onBeforeUnmount(() => {
  82. $unsub('shop-vite-reset-dark')
  83. })
  84. </script>
  85. <style lang="scss">
  86. ::view-transition-old(root),
  87. ::view-transition-new(root) {
  88. mix-blend-mode: normal;
  89. animation: none;
  90. }
  91. ::view-transition-old(root) {
  92. z-index: 999;
  93. }
  94. ::view-transition-new(root) {
  95. z-index: 1;
  96. }
  97. .dark {
  98. &::view-transition-old(root) {
  99. z-index: 1;
  100. }
  101. &::view-transition-new(root) {
  102. z-index: 999;
  103. }
  104. }
  105. .vab-dark {
  106. margin-left: var(--el-margin);
  107. }
  108. </style>