个人技术总结——Vue3的的Provide和Inject功能

222100404余诗怡 2024-06-03 15:22:50
这个作业属于哪个课程2302软件工程
这个作业要求在哪里软件工程实践总结&个人技术博客
这个作业的目标完成软工实践过程中的总结
其他参考文献....

使用Vue3的Provide和Inject实现项目的主题切换

目录

  • 使用Vue3的Provide和Inject实现项目的主题切换
  • 1.技术概述
  • 2.技术详述
  • 3.技术使用中遇到的问题和解决过程
  • 4.总结
  • 5.参考文献

在我们的团队项目中,需要实现深浅色主题的切换,于是我使用了provide和inject功能实现了动态主题切换。这个功能允许用户在浅色模式和深色模式之间切换,并且能够跟随系统的主题设置。这篇博客将详细介绍实现过程,包括代码示例和遇到的问题及解决方案。

1.技术概述

Vue3的provide和inject用于实现祖先组件与后代组件之间的依赖注入,简化了深层次组件树中的数据传递。在这个项目中,使用provide和inject来管理主题切换功能,使主题状态在多个组件间共享。学习和使用这一技术是为了更好地管理全局状态,提高代码的可维护性和可读性。

2.技术详述

  1. 父组件 (App.vue) 中使用provide提供主题状态和切换方法

在父组件中定义了一个状态对象state,包含了主题相关的属性,如当前主题、是否跟随系统主题、是否为深色模式等。并通过provide将state和toggleTheme方法传递给子组件。


<!-- App.vue -->
<template>
  <RouterLink to="/">Home</RouterLink>
  <RouterView />
</template>

<script setup lang="ts">
import { reactive, provide, onMounted } from 'vue';

interface State {
  isSunny: boolean;
  theme: 'light' | 'dark';
  followSystemTheme: boolean;
  darkMode: boolean;
}

const state = reactive<State>({
  isSunny: true,
  theme: 'light',
  followSystemTheme: true,
  darkMode: false,
});

// 切换主题
const toggleTheme = () => {
  state.followSystemTheme = false;
  state.theme = state.theme === 'light' ? 'dark' : 'light';
  state.isSunny = state.theme === 'light';
  state.darkMode = state.theme === 'dark';
  document.documentElement.setAttribute('data-theme', state.theme);
  localStorage.setItem('theme', state.theme);
  localStorage.setItem('followSystemTheme', JSON.stringify(state.followSystemTheme));
};

// 监听系统主题变化
const updateThemeFromSystem = (e: MediaQueryListEvent) => {
  if (state.followSystemTheme) {
    state.theme = e.matches ? 'dark' : 'light';
    state.isSunny = state.theme === 'light';
    state.darkMode = state.theme === 'dark';
    document.documentElement.setAttribute('data-theme', state.theme);
    localStorage.setItem('theme', state.theme);
  }
};

const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkModeMediaQuery.addEventListener('change', updateThemeFromSystem);

provide('state', state);
provide('toggleTheme', toggleTheme);

onMounted(() => {
  const savedTheme = localStorage.getItem('theme');
  const savedFollowSystemTheme = localStorage.getItem('followSystemTheme');

  if (savedTheme) {
    state.theme = savedTheme as 'light' | 'dark';
    state.isSunny = savedTheme === 'light';
    state.darkMode = savedTheme === 'dark';
    document.documentElement.setAttribute('data-theme', savedTheme);
  }

  if (savedFollowSystemTheme) {
    state.followSystemTheme = JSON.parse(savedFollowSystemTheme);
  } else {
    state.followSystemTheme = true;
  }

  if (state.followSystemTheme && darkModeMediaQuery.matches) {
    updateThemeFromSystem(darkModeMediaQuery);
  }
});
</script>
  1. 子组件 (ColorSetting.vue) 中使用inject获取并使用主题状态

在子组件中,通过inject获取父组件提供的state和toggleTheme,并实现主题切换和系统主题跟随的功能。


<!-- ColorSetting.vue -->
<template>
  <div>
    <SwitchToggle :value="state.darkMode" @change="handleDarkModeToggle" />
    <SwitchToggle :value="state.followSystemTheme" @change="updateFollowSystemTheme" label="Follow System Theme" />
  </div>
</template>

<script setup lang="ts">
import { inject, onMounted } from 'vue';

const defaultState = {
  isSunny: true,
  theme: 'light',
  followSystemTheme: true,
  darkMode: false,
};
const state = inject('state', defaultState);

function applyThemeSettings() {
  document.documentElement.setAttribute('data-theme', state.theme);
  localStorage.setItem('theme', state.theme);
  localStorage.setItem('isSunny', JSON.stringify(state.isSunny));
  localStorage.setItem('followSystemTheme', JSON.stringify(state.followSystemTheme));
  localStorage.setItem('darkMode', JSON.stringify(state.darkMode));
}

const handleDarkModeToggle = (value: boolean) => {
  state.followSystemTheme = false;
  state.darkMode = value;
  state.theme = state.darkMode ? 'dark' : 'light';
  state.isSunny = !state.darkMode;
  applyThemeSettings();
};

const updateFollowSystemTheme = (value: boolean) => {
  state.followSystemTheme = value;
  if (value) {
    const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    const newTheme = darkModeMediaQuery.matches ? 'dark' : 'light';
    state.theme = newTheme;
    state.isSunny = newTheme === 'light';
    state.darkMode = newTheme === 'dark';
    applyThemeSettings();
    darkModeMediaQuery.addEventListener('change', updateThemeFromSystem);
  } else {
    const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    darkModeMediaQuery.removeEventListener('change', updateThemeFromSystem);
    applyThemeSettings();
  }
};

const updateThemeFromSystem = (e: MediaQueryListEvent) => {
  if (state.followSystemTheme) {
    state.theme = e.matches ? 'dark' : 'light';
    state.isSunny = state.theme === 'light';
    state.darkMode = state.theme === 'dark';
    applyThemeSettings();
  }
};

onMounted(() => {
  const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
  state.theme = localStorage.getItem('theme') as 'light' | 'dark' || 'light';
  state.isSunny = JSON.parse(localStorage.getItem('isSunny') || 'true');
  state.followSystemTheme = JSON.parse(localStorage.getItem('followSystemTheme') || 'true');
  state.darkMode = state.theme === 'dark';
  applyThemeSettings();

  if (state.followSystemTheme) {
    darkModeMediaQuery.addEventListener('change', updateThemeFromSystem);
  }
});
</script>

3.技术使用中遇到的问题和解决过程

问题1:动态主题切换时的状态同步

描述:在切换主题时,确保所有依赖该状态的组件能够实时响应状态变化。

解决方案:
使用Vue的响应式特性(reactive)来管理状态,确保状态变化能够自动更新所有使用该状态的组件。

const state = reactive<State>({
  isSunny: true,
  theme: 'light',
  followSystemTheme: true,
  darkMode: false,
});

问题2:监听系统主题变化

描述:需要在用户手动切换主题和系统主题变化时保持同步。

解决方案:
通过window.matchMedia监听系统主题变化,并在状态变化时更新DOM和本地存储。


const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkModeMediaQuery.addEventListener('change', updateThemeFromSystem);

4.总结

通过使用Vue3的provide和inject功能,我实现了一个高效的主题切换功能,使用户能够在浅色模式和深色模式之间自由切换,并且能够跟随系统主题设置。通过管理全局状态,解决了组件间数据传递的复杂性,提高了代码的可维护性和可读性。遇到的问题如状态同步和系统主题监听,通过响应式特性和媒体查询事件处理得到了有效解决。

5.参考文献

Vue.js 官方文档
Vue3 provide 和 inject 介绍
Element Plus 官方文档

...全文
99 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

122

社区成员

发帖
与我相关
我的任务
社区描述
FZU-SE
软件工程 高校
社区管理员
  • LinQF39
  • 助教-吴可仪
  • 一杯时间
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧