feat(app): 添加暗黑模式支持并优化主题样式
- 新增暗黑模式支持,使用 colorMode 模块管理主题切换 - 添加全局样式和默认主题样式文件 - 优化 app.vue 中的样式和布局 - 更新 i18n 插件配置,使用 TypeScript 类型 - 调整 nuxt.config.js 中的模块顺序和配置
This commit is contained in:
parent
88d1dea0d2
commit
107966dabc
21
app/app.vue
21
app/app.vue
@ -1,15 +1,17 @@
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {message} from '@/components/x-message/useMessage.js'
|
||||
// message.success('success')
|
||||
useHead({
|
||||
title: useI18n().t('appSetting.appName'),
|
||||
meta: [
|
||||
{ name: 'description', content: useI18n().t('appSetting.appDescription') },
|
||||
{ name: 'keywords', content: useI18n().t('appSetting.appKeyWords') },
|
||||
{name: 'description', content: useI18n().t('appSetting.appDescription')},
|
||||
{name: 'keywords', content: useI18n().t('appSetting.appKeyWords')},
|
||||
],
|
||||
})
|
||||
const color = useColorMode()
|
||||
const mode = computed(() => {
|
||||
return ''
|
||||
return color.value
|
||||
})
|
||||
|
||||
// 添加路由中间件来处理过渡方向
|
||||
@ -40,13 +42,13 @@ provide('slideDirection', slideDirection)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VanConfigProvider theme="light">
|
||||
<VanConfigProvider :theme="mode">
|
||||
<NuxtLoadingIndicator
|
||||
color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)" />
|
||||
color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)"/>
|
||||
<NuxtLayout>
|
||||
<NuxtPage :transition="{
|
||||
name: slideDirection
|
||||
}" />
|
||||
}"/>
|
||||
</NuxtLayout>
|
||||
</VanConfigProvider>
|
||||
</template>
|
||||
@ -76,7 +78,8 @@ provide('slideDirection', slideDirection)
|
||||
.slide-right-leave-to {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
:root{
|
||||
|
||||
:root {
|
||||
--safe-area-inset-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
@ -1,4 +1,4 @@
|
||||
|
||||
import type { Locale as TypeLocale } from '#i18n'
|
||||
import { Locale } from 'vant'
|
||||
import enUS from 'vant/es/locale/lang/en-US'
|
||||
import zhCN from 'vant/es/locale/lang/zh-CN'
|
||||
@ -6,7 +6,7 @@ import jaJP from 'vant/es/locale/lang/ja-JP'
|
||||
import zhTW from 'vant/es/locale/lang/zh-TW'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
|
||||
// 载入 vant 语言包
|
||||
Locale.use('zh-CN', zhCN)
|
||||
Locale.use('en-US', enUS)
|
||||
Locale.use('ja-JP', jaJP)
|
||||
@ -15,9 +15,11 @@ export default defineNuxtPlugin(() => {
|
||||
if (import.meta.client) {
|
||||
const i18n = useNuxtApp().$i18n
|
||||
const { setLocale } = i18n
|
||||
|
||||
const lang = localStorage.getItem('lang')
|
||||
|
||||
if (lang) {
|
||||
setLocale(lang)
|
||||
setLocale(lang as TypeLocale)
|
||||
Locale.use(lang)
|
||||
}
|
||||
else {
|
4
app/styles/default-theme.css
Normal file
4
app/styles/default-theme.css
Normal file
@ -0,0 +1,4 @@
|
||||
:root:root {
|
||||
--van-primary-color: var(--c-primary);
|
||||
--van-cell-group-inset-padding: 0;
|
||||
}
|
14
app/styles/global.css
Normal file
14
app/styles/global.css
Normal file
@ -0,0 +1,14 @@
|
||||
#__nuxt {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
background: var(--van-gray-1);
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
background: #222;
|
||||
color-scheme: dark;
|
||||
}
|
4
app/styles/vars.css
Normal file
4
app/styles/vars.css
Normal file
@ -0,0 +1,4 @@
|
||||
:root {
|
||||
--c-primary: #3554AF;
|
||||
--c-primary-active: #3554AF;
|
||||
}
|
195
nuxt.config.js
195
nuxt.config.js
@ -1,18 +1,9 @@
|
||||
// 导入环境变量处理库
|
||||
import dotenv from 'dotenv'
|
||||
// 导入 Node.js 进程模块
|
||||
import process from 'node:process'
|
||||
// 导入预加载工具函数
|
||||
import preload from './app/utils/preload'
|
||||
// 导入国际化语言配置
|
||||
import { currentLocales } from './i18n/i18n'
|
||||
|
||||
// 设置环境变量文件路径,默认使用 .env.test
|
||||
const envFile = process.env.ENV_FILE || '.env.test'
|
||||
// 加载环境变量配置
|
||||
dotenv.config({ path: `./env/${envFile}` })
|
||||
|
||||
// 过滤出以 NUXT_PUBLIC_ 开头的环境变量作为公共配置
|
||||
const publicConfig = Object.entries(process.env)
|
||||
.filter(([key]) => key.startsWith('NUXT_PUBLIC_'))
|
||||
.reduce((config, [key, value]) => {
|
||||
@ -21,38 +12,38 @@ const publicConfig = Object.entries(process.env)
|
||||
}, {})
|
||||
|
||||
export default defineNuxtConfig({
|
||||
// 注册 Nuxt 模块
|
||||
modules: [
|
||||
'@nuxt/image', // 图片优化模块
|
||||
'@vant/nuxt', // Vant UI 组件库
|
||||
'@unocss/nuxt', // 原子化 CSS 框架
|
||||
'@nuxtjs/i18n', // 国际化模块
|
||||
],
|
||||
|
||||
// 运行时配置
|
||||
modules: [
|
||||
'@vant/nuxt',
|
||||
'@unocss/nuxt',
|
||||
'@nuxt/image',
|
||||
'@nuxtjs/color-mode',
|
||||
'@nuxtjs/i18n',
|
||||
],
|
||||
runtimeConfig: {
|
||||
// 私有配置,只在服务端可用
|
||||
// 私有配置,只有在服务端可用
|
||||
apiSecret: process.env.NUXT_API_SECRET || 'default_secret',
|
||||
// 公共配置,客户端和服务端都可用
|
||||
public: publicConfig,
|
||||
},
|
||||
|
||||
// CSS 配置
|
||||
css: [
|
||||
'@unocss/reset/tailwind.css', // 重置默认样式
|
||||
'@unocss/reset/tailwind.css',
|
||||
'@/static/styles/default-theme.css',
|
||||
],
|
||||
// PostCSS 配置
|
||||
|
||||
postcss: {
|
||||
plugins: {
|
||||
'autoprefixer': {}, // 自动添加 CSS 前缀
|
||||
// 移动端适配插件配置
|
||||
'autoprefixer': {},
|
||||
|
||||
// https://github.com/wswmsword/postcss-mobile-forever
|
||||
'postcss-mobile-forever': {
|
||||
appSelector: '#__nuxt', // 根选择器
|
||||
viewportWidth: 375, // 设计稿宽度
|
||||
maxDisplayWidth: 600, // 最大显示宽度
|
||||
exclude: /@nuxt/, // 排除的文件
|
||||
border: true, // 显示边框
|
||||
appSelector: '#__nuxt',
|
||||
viewportWidth: 375,
|
||||
maxDisplayWidth: 600,
|
||||
// devtools excluded
|
||||
exclude: /@nuxt/,
|
||||
border: true,
|
||||
rootContainingBlockSelectorList: [
|
||||
'van-tabbar',
|
||||
'van-popup',
|
||||
@ -61,153 +52,89 @@ export default defineNuxtConfig({
|
||||
},
|
||||
},
|
||||
|
||||
// 国际化配置
|
||||
i18n: {
|
||||
locales: currentLocales, // 支持的语言列表
|
||||
lazy: true, // 懒加载语言包
|
||||
strategy: 'no_prefix', // URL 策略:不添加语言前缀
|
||||
detectBrowserLanguage: {
|
||||
useCookie: true, // 使用 cookie 存储语言选择
|
||||
cookieKey: 'i18n_redirected', // cookie 键名
|
||||
redirectOn: 'root', // 仅在根路径重定向
|
||||
alwaysRedirect: true, // 总是重定向
|
||||
fallbackLocale: 'zh-CN' // 默认语言
|
||||
},
|
||||
langDir: 'locales', // 语言文件目录
|
||||
defaultLocale: 'zh-CN', // 默认语言
|
||||
vueI18n: './i18n/i18n.config.ts', // Vue I18n 配置文件
|
||||
colorMode: {
|
||||
classSuffix: '',
|
||||
preference: 'system',
|
||||
fallback: 'light',
|
||||
storageKey: 'nuxt-color-mode',
|
||||
},
|
||||
|
||||
i18n: {
|
||||
locales: currentLocales,
|
||||
lazy: true,
|
||||
strategy: 'no_prefix',
|
||||
detectBrowserLanguage: {
|
||||
useCookie: true,
|
||||
cookieKey: 'i18n_redirected',
|
||||
redirectOn: 'root',
|
||||
alwaysRedirect: true,
|
||||
fallbackLocale: 'zh-CN'
|
||||
},
|
||||
langDir: 'locales',
|
||||
defaultLocale: 'zh-CN',
|
||||
vueI18n: './i18n/i18n.config.ts',
|
||||
},
|
||||
|
||||
// 应用配置
|
||||
app: {
|
||||
// 布局过渡动画
|
||||
layoutTransition: {
|
||||
name: 'layout',
|
||||
mode: 'out-in'
|
||||
},
|
||||
// 头部配置
|
||||
head: {
|
||||
// 视口配置
|
||||
viewport: 'width=device-width,initial-scale=1,viewport-fit=cover',
|
||||
// 链接配置
|
||||
link: [
|
||||
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' }, // 网站图标
|
||||
{ rel: 'preload', as: 'style', href: '/critical.css' }, // 预加载关键 CSS
|
||||
{ rel: 'preconnect', href: '你的API域名' }, // 预连接 API 域名
|
||||
{ rel: 'dns-prefetch', href: '你的API域名' }, // DNS 预解析
|
||||
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' },
|
||||
],
|
||||
// Meta 标签配置
|
||||
meta: [
|
||||
{ name: 'apple-mobile-web-app-capable', content: 'yes' }, // iOS 应用模式
|
||||
{ name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' }, // iOS 状态栏样式
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: light)', content: '#ffffff' }, // 浅色主题色
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: dark)', content: '#222222' }, // 深色主题色
|
||||
{ name: 'description', content: '你的网站描述' }, // SEO 描述
|
||||
{ 'http-equiv': 'x-dns-prefetch-control', content: 'on' }, // DNS 预解析控制
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1, viewport-fit=cover,user-scalable=no' },
|
||||
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
|
||||
{ name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: light)', content: '#ffffff' },
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: dark)', content: '#222222' },
|
||||
],
|
||||
// 脚本配置
|
||||
script: [
|
||||
{ innerHTML: preload(), type: 'text/javascript', tagPosition: 'head' }, // 预加载脚本
|
||||
// 性能监控脚本
|
||||
{
|
||||
innerHTML: `
|
||||
window.performance.mark('app-start');
|
||||
new PerformanceObserver((entryList) => {
|
||||
for (const entry of entryList.getEntries()) {
|
||||
console.log('FCP:', entry.startTime);
|
||||
}
|
||||
}).observe({entryTypes: ['paint']});
|
||||
`,
|
||||
type: 'text/javascript',
|
||||
tagPosition: 'head'
|
||||
}
|
||||
{ innerHTML: preload(), type: 'text/javascript', tagPosition: 'head' },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// Vite 构建配置
|
||||
vite: {
|
||||
build: {
|
||||
target: 'esnext', // 构建目标
|
||||
// Rollup 配置
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
'vant': ['vant'], // Vant 单独打包
|
||||
'vendor': ['vue', 'vue-router'] // 核心库单独打包
|
||||
}
|
||||
}
|
||||
},
|
||||
minify: 'terser', // 使用 terser 压缩
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true, // 移除 console
|
||||
drop_debugger: true // 移除 debugger
|
||||
}
|
||||
}
|
||||
target: 'esnext',
|
||||
},
|
||||
// 依赖优化配置
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'@intlify/core-base', // I18n 核心
|
||||
'@intlify/shared', // I18n 共享库
|
||||
'is-https', // HTTPS 检测
|
||||
'vant', // Vant UI
|
||||
'@vant/use', // Vant Hooks
|
||||
'@vueuse/core', // VueUse 工具集
|
||||
'@intlify/core-base',
|
||||
'@intlify/shared',
|
||||
'is-https',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// 实验性功能
|
||||
experimental: {
|
||||
typedPages: true, // 启用页面类型
|
||||
typedPages: true,
|
||||
},
|
||||
|
||||
// 开发工具
|
||||
devtools: {
|
||||
enabled: true, // 启用开发工具
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
// TypeScript 配置
|
||||
typescript: {
|
||||
shim: false, // 禁用 shim
|
||||
shim: false,
|
||||
},
|
||||
|
||||
// 功能特性配置
|
||||
features: {
|
||||
inlineStyles: false, // 禁用内联样式
|
||||
// For UnoCSS
|
||||
inlineStyles: false,
|
||||
},
|
||||
|
||||
// 未来特性配置
|
||||
future: {
|
||||
compatibilityVersion: 4, // 兼容性版本
|
||||
compatibilityVersion: 4,
|
||||
},
|
||||
|
||||
// Nuxt 兼容性日期
|
||||
compatibilityDate: '2025-01-09', // 确保未来版本兼容性
|
||||
|
||||
// 开发服务器配置
|
||||
// 指定 Nuxt 应用程序的兼容性日期,确保应用程序在未来的 Nuxt 版本中保持稳定性
|
||||
compatibilityDate: '2025-01-09',
|
||||
devServer: {
|
||||
host: '0.0.0.0', // 主机地址
|
||||
port: 3000, // 端口号
|
||||
host: '0.0.0.0', // Set the host to 'localhost'
|
||||
port: 3000, // Set the port to 3000 or any other port you prefer
|
||||
},
|
||||
|
||||
// 图片优化配置
|
||||
image: {
|
||||
provider: 'ipx', // 图片处理提供者
|
||||
// 响应式断点
|
||||
screens: {
|
||||
xs: 320, // 超小屏幕
|
||||
sm: 640, // 小屏幕
|
||||
md: 768, // 中等屏幕
|
||||
lg: 1024, // 大屏幕
|
||||
xl: 1280, // 超大屏幕
|
||||
xxl: 1536, // 特大屏幕
|
||||
},
|
||||
quality: 80, // 图片质量
|
||||
format: ['webp', 'jpg'], // 支持的格式
|
||||
placeholder: true, // 启用占位图
|
||||
blur: 3 // 模糊加载效果
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user