122
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | 2302软件工程 |
|---|---|
| 这个作业要求在哪里 | 软件工程实践总结&个人技术博客 |
| 这个作业的目标 | 完成软工实践过程中的总结 |
| 其他参考文献 | .... |
Vue3的provide和inject用于实现祖先组件与后代组件之间的依赖注入,简化了深层次组件树中的数据传递。在这个项目中,使用provide和inject来管理主题切换功能,使主题状态在多个组件间共享。学习和使用这一技术是为了更好地管理全局状态,提高代码的可维护性和可读性。
在父组件中定义了一个状态对象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>
在子组件中,通过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>
问题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);
通过使用Vue3的provide和inject功能,我实现了一个高效的主题切换功能,使用户能够在浅色模式和深色模式之间自由切换,并且能够跟随系统主题设置。通过管理全局状态,解决了组件间数据传递的复杂性,提高了代码的可维护性和可读性。遇到的问题如状态同步和系统主题监听,通过响应式特性和媒体查询事件处理得到了有效解决。