交互方案
前一篇文章,记录了从零开始搭建一个 Nuxt + PrimeVue + TailwindCss 的最小化项目。今天继续给它增加一个非常酷的功能:暗黑模式切换。
一般来说,暗黑模式的切换,有四个方案:
- 方案一:三个选项,浅色、暗黑、跟随系统,用下拉菜单选择
- 优点:提供更多的选择,用户可以根据自己的需求选择跟随系统设置。
- 缺点:增加了操作复杂度,用户需要在三个选项中进行选择。至少要点击 2 次。
- 方案二,二个选项,浅色、暗黑,用一个图标点击切换
- 优点:简化了操作,用户只需在浅色和深色之间切换。
- 缺点:失去了跟随系统设置的功能。
- 方案三:三个选项,平排放三个图标供用户点击
- 优点:简化操作,只需要点击一下
- 缺点:并排放三个图标,尤其是在工具栏这种地方,比较难看,且容易暄宾夺主,
- 方案四:三个选项,只放一个图标,点击轮换
- 优点:操作简化,配合图标和文字,也不用做多余的提示
- 缺点:要切换回第一个值,要点两下
参考 Nuxt、PrimeVue 都只是提供了一个图标点击的方案,也就是两个选项,要么浅色,要么深色。我觉得两个选项也够用,用户点击一次就可以。
但是开发调试的时候就发现还是方案四比较好玩儿。所以我选方案四,一个图标,三个选项轮换。
那么如何保持用户的选择呢?仍然是少不了使用 cookie 或 localStorage 来记录。这里就要用到一个 Nuxt 的组件 @nuxtjs/color-mode
。它能配置存在哪里,选择器的前缀、后缀。还能根据系统主题的切换自动来切换。
实现暗黑模式切换
就像 Nuxt 网站一样,先要有个图标,然后点击后切换深/浅色,同时图标也变成对应的另一个图标。这时候需要安装一个 PrimeVue 的图标库。当然,也有其它的很多图标库可以选,这里我先用 primeicons
。
1
2
| npm install primeicons
npx nuxi module add color-mode
|
然后需要简单配置一下 nuxt.config.ts
在 modules 同级增加图标库的 css 引入,以及 colorMode
的配置:
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
| // https://nuxt.com/docs/api/configuration/nuxt-config
import Aura from "@primevue/themes/aura";
export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
devtools: { enabled: true },
modules: ["@primevue/nuxt-module", "@nuxtjs/tailwindcss", "@nuxtjs/color-mode"],
css: [
'primeicons/primeicons.css',
],
colorMode: {
classSuffix: '', // 类名后缀,默认值"-mode",如果不加前缀和后缀,类名为 'dark'|'light',此时 Nuxt DevTools 也会跟着切换颜色模式
preference: 'light', // 默认偏好:'system' | 'light' | 'dark'
fallback: 'light', // 回退模式
dataValue: 'theme', // HTML 数据属性名
storage: 'localStorage', // 存储方式:'localStorage' | 'cookie'
storageKey: 'nuxt-color-mode', // 存储键名
},
primevue: {
autoImport: true, // 自动导入 PrimeVue 组件
options: {
ripple: true, // 是否启用涟漪效果
theme: {
preset: Aura, // 预设的主题,没有主题不显示样式
options: {
darkModeSelector: '.dark', // 暗黑模式选择器,对应 colorMode.classPrefix + {light|dark} + colorMode.classSuffix
}
},
},
},
});
|
然后components/AppHeader.vue
的 script
部分增加代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| const colorMode = useColorMode()
// 定义模式顺序:light -> dark -> system -> light
const modes = ['dark', 'light', 'system']
// 计算当前图标
const modeIcon = computed(() => {
switch (colorMode.preference) {
case 'dark':
return 'pi pi-moon'
case 'light':
return 'pi pi-sun'
default:
return 'pi pi-desktop'
}
})
// 切换模式
const toggleMode = () => {
const currentIndex = modes.indexOf(colorMode.preference)
const nextIndex = (currentIndex + 1) % modes.length
colorMode.preference = modes[nextIndex]
}
|
然后在登录
按钮前面增加图标选择的按钮
1
2
3
4
5
6
7
8
9
10
11
12
| <client-only>
<Button
@click="toggleMode"
outlined
class="flex items-center gap-2 p-button-text"
>
<span class="pi" :class="modeIcon"></span>
<span v-if="colorMode.preference === 'light'">Light</span>
<span v-if="colorMode.preference === 'dark'">Dark</span>
<span v-if="colorMode.preference === 'system'">Auto</span>
</Button>
</client-only>
|
然后点击页面中的图标就可以看到效果了。但是。为什么只有头部 header 部分变黑,其它地方没有变黑呢?这是因为 app.vue
中还在引入 <NuxtWelcome />
组件。该组件有自己的控制方式。所以我们移除它,修改 app.vue
成这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <template>
<div>
<AppHeader />
<main class="pt-[60px] min-h-[calc(100vh-60px)]">
<div class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold">
欢迎使用
</h1>
<p class="mt-4">
这是一个支持暗黑模式的页面
</p>
</div>
</main>
</div>
</template>
|
就可以了。点击暗黑切换按钮试试吧。
代码还是在这里:https://github.com/wkii/nuxt-primevue-tailwindcss-starter