首页 > 解决方案 > Vue - 当 vuex 存储中的值更改时删除侦听器

问题描述

我的暗模式设置有一个组件,如下所示:
在此处输入图像描述

Automatic - 从 OS 获取设置
Light - 应用浅色主题覆盖 OS 设置
Dark - 应用深色主题覆盖 OS 设置

出了什么问题
目前,当我切换到“浅色”或“深色”,然后开始在我的 Windows 设置中更改首选配色方案时,它仍然会不断切换到我在那里选择的任何颜色。当设置不是自动的时,应该忽略它。

我认为正在发生的事情
我猜它eventListener仍然存在,并且应该在用户选择“浅色”或“深色”时被销毁。我尝试使用 aAbortController()但没有成功。

app.vue
在我的 app.vue 中,我查看当前设置,如果它是“自动”的,我会设置一个初始主题并EventListener从操作系统中获取更改。

  created() {
    this.$store.watch(
      (state) => {
        return state.settings.colorSettings.automatic;
      },
      (currentAutomaticValue) => { 
        if (currentAutomaticValue) { //if automatic is true
          if (
            window.matchMedia &&
            window.matchMedia("(prefers-color-scheme: dark)").matches
          ) {
            document
              .getElementsByTagName("html")[0]
              .setAttribute("theme", "theme-dark");
          } else {
            document
              .getElementsByTagName("html")[0]
              .setAttribute("theme", "theme-default");
          }
          window
            .matchMedia("(prefers-color-scheme: dark)")
            .addEventListener("change", (e) => {
              const darkMode = e.matches ? true : false;
              document
                .getElementsByTagName("html")[0]
                .setAttribute(
                  "theme",
                  darkMode ? "theme-dark" : "theme-default"
                );
            });
        }
      },
      { immediate: true }
    );

switchComponent.vue
在这里,当所选值更改时,我运行一个函数。这个函数看起来像这样:

methods: {
    onSwitch(event) {
      if (!this.colorSettings?.loading) {
        switch (event.target.id) {
          case "automatic":
            this.colorSettings.automatic = true;
            break;
          case "light":
            this.colorSettings.darkMode = false;
            this.colorSettings.automatic = false;
            break;
          case "dark":
            this.colorSettings.darkMode = true;
            this.colorSettings.automatic = false;
            break;
        }

        this.$store.dispatch("setDarkMode", this.colorSettings);

        document
          .getElementsByTagName("html")[0]
          .setAttribute(
            "theme",
            this.colorSettings.darkMode ? "theme-dark" : "theme-default"
          );
      }
    },
  }

Settings.js 状态

import { SettingsService } from "@/api/settingsService";

const state = {
  colorSettings: {
    loading: false,
    automatic: true,
    darkMode: false,
    colors: {}
  }
};

const getters = {
  loadingColorSettings: state => {
    return state.colorSettings.loading;
  },
  colorSettings: state => {
    return state.colorSettings;
  }
};

const mutations = {
  SET_COLOR_SETTINGS(state, colorSettings) {
    state.colorSettings.automatic = colorSettings.automatic;
    state.colorSettings.darkMode = colorSettings.darkMode;
    state.colorSettings.colors = colorSettings.entityTypeColors;
  },
  SET_LOADING_COLOR_SETTINGS(state, isLoading) {
    state.colorSettings.loading = isLoading;
  }
};

const actions = {
  setDarkMode: (context, updatedDarkmode) => {
    context.commit("SET_LOADING_COLOR_SETTINGS", true);
    SettingsService.setColoring(updatedDarkmode)
      .then(response => {
        context.commit("SET_COLOR_SETTINGS", response.data);
      })
      .catch(resp => {
        console.error(resp);
      })
      .finally(() => {
        context.commit("SET_LOADING_COLOR_SETTINGS", false);
      });
  }
};

export ...

任何人都可以向我推动正确的方向吗?

标签: javascriptvue.jsvuex

解决方案


EventListener因此,毕竟删除显然是有效的。我之前尝试过这样做,但当时没有让它工作。

代码需要优化(非常欢迎提出建议!),代码看起来很乱。但这是一个开始。

我做了什么:

  • 为侦听器制作了一个单独的功能setTheme(),以便我可以将其删除

  • 必须window.matchMedia("(prefers-color-scheme: dark)")输入一个常数,这也是能够删除它的必要条件

  • 当观察者认为currentAutomaticValue是假的时移除监听者

     methods: {
      setTheme(e) {
        const darkMode = e.matches ? true : false;
        document
          .getElementsByTagName("html")[0]
          .setAttribute(
            "theme",
            darkMode ? "theme-dark" : "theme-default"
          );
      }
    },
    created() {
      const media = window.matchMedia("(prefers-color-scheme: dark)");
    
      this.$store.watch(
        (state) => {
          return state.settings.colorSettings.automatic;
        },
        (currentAutomaticValue) => {
          if (currentAutomaticValue) {
            if (
              window.matchMedia &&
              window.matchMedia("(prefers-color-scheme: dark)").matches
            ) {
              document
                .getElementsByTagName("html")[0]
                .setAttribute("theme", "theme-dark");
            } else {
              document
                .getElementsByTagName("html")[0]
                .setAttribute("theme", "theme-default");
            }
            media.addEventListener("change", this.setTheme);
          } else {
            media.removeEventListener("change", this.setTheme);
            if (this.colorSettings.darkMode) {
              document
                .getElementsByTagName("html")[0]
                .setAttribute("theme", "theme-dark");
            } else {
              document
                .getElementsByTagName("html")[0]
                .setAttribute("theme", "theme-default");
            }
          }
        },
        { immediate: true }
      );
    }
    

推荐阅读