zhuguifei
2025-06-17 c1cc49dd93d38f51790558541d6835d1598ecccf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { defineStore } from "pinia";
import { store } from "@/store";
import { nextTick } from "vue";
import { isDarkMode, updateDarkMode } from "@/utils/dark-mode";
 
export const useDarkModeStore = defineStore({
  id: "dark-mode",
  state: () => ({
    darkMode: isDarkMode()
  }),
  actions: {
    toggleDarkMode(event?: TouchEvent | MouseEvent) {
      const isAppearanceTransition =
        "startViewTransition" in document &&
        !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
 
      const toggle = () => {
        this.darkMode = !this.darkMode;
        updateDarkMode(this.darkMode);
      };
 
      if (!isAppearanceTransition) {
        toggle();
        return;
      }
 
      let x: number, y: number;
      if (event instanceof TouchEvent) {
        x = event.touches[0].clientX;
        y = event.touches[0].clientY;
      } else if (event instanceof MouseEvent) {
        x = event.clientX;
        y = event.clientY;
      } else {
        // 如果没有事件对象,使用屏幕右上角作为默认位置
        x = window.innerWidth;
        y = 0;
      }
      const endRadius = Math.hypot(
        Math.max(x, window.innerWidth - x),
        Math.max(y, window.innerHeight - y)
      );
 
      const transition = (document as any).startViewTransition(async () => {
        toggle();
        await nextTick();
      });
 
      transition.ready.then(() => {
        const clipPath = [
          `circle(0px at ${x}px ${y}px)`,
          `circle(${endRadius}px at ${x}px ${y}px)`
        ];
        document.documentElement.animate(
          {
            clipPath: this.darkMode ? [...clipPath].reverse() : clipPath
          },
          {
            duration: 400,
            easing: "ease-out",
            pseudoElement: this.darkMode
              ? "::view-transition-old(root)"
              : "::view-transition-new(root)"
          }
        );
      });
    }
  }
});
 
export function useDarkModeStoreHook() {
  return useDarkModeStore(store);
}