refactor(app): 重构应用配置和样式

- 移除 colorMode 相关代码
- 删除全局样式文件
- 更新 nuxt 配置:
  - 添加 runtimeConfig
  - 更新 css 配置
  - 优化 vite构建配置
  - 新增 image 模块配置
- 更新路由配置
- 调整组件实现
- 更新环境变量加载方式
This commit is contained in:
xingyy 2025-01-23 13:56:18 +08:00
parent fb8a72b47a
commit 3b8bd623c0
12 changed files with 759 additions and 172 deletions

View File

@ -1,7 +1,6 @@
<script setup> <script setup>
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import {message} from '@/components/x-message/useMessage.js'
// message.success('success')
useHead({ useHead({
title: useI18n().t('appSetting.appName'), title: useI18n().t('appSetting.appName'),
meta: [ meta: [
@ -9,10 +8,6 @@ useHead({
{ name: 'keywords', content: useI18n().t('appSetting.appKeyWords') }, { name: 'keywords', content: useI18n().t('appSetting.appKeyWords') },
], ],
}) })
const color = useColorMode()
const mode = computed(() => {
return color.value
})
// //
const router = useRouter() const router = useRouter()
@ -42,7 +37,7 @@ provide('slideDirection', slideDirection)
</script> </script>
<template> <template>
<VanConfigProvider :theme="mode"> <VanConfigProvider>
<NuxtLoadingIndicator <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> <NuxtLayout>

View File

@ -1,9 +1,8 @@
<script setup> <script setup>
import { useAppFooterRouteNames as names } from '~/config/index.js' import { useAppFooterRouteNames as names } from '@/config/index.js'
import MyIcon from "~/components/icons/MyIcon.vue"; import MyIcon from "@/components/icons/MyIcon.vue";
import HomeIcon from "~/components/icons/HomeIcon.vue"; import HomeIcon from "@/components/icons/HomeIcon.vue";
const route = useRoute() const route = useRoute()
const active = ref(0) const active = ref(0)
const show = computed(() => { const show = computed(() => {
if (route.name && names.includes(route.name)) if (route.name && names.includes(route.name))
@ -13,7 +12,6 @@ const show = computed(() => {
const initData=()=>{ const initData=()=>{
active.value=route.path==='/profile'?1:0 active.value=route.path==='/profile'?1:0
} }
onMounted(()=>{ onMounted(()=>{
initData() initData()
}) })
@ -21,7 +19,6 @@ onMounted(()=>{
<template> <template>
<div v-if="show"> <div v-if="show">
<van-tabbar v-model="active" route placeholder fixed> <van-tabbar v-model="active" route placeholder fixed>
<van-tabbar-item replace to="/"> <van-tabbar-item replace to="/">
<span>{{ $t('tabbar.home') }}</span> <span>{{ $t('tabbar.home') }}</span>

View File

@ -1,8 +1,6 @@
<script setup> <script setup>
/*
* 此组件的目的是使用该图片组件自带预览大图
* */
import { showImagePreview } from 'vant'; import { showImagePreview } from 'vant';
import { NuxtImg } from '#components'
const props = defineProps({ const props = defineProps({
src: { src: {
type: String, type: String,
@ -11,19 +9,48 @@ const props = defineProps({
preview: { preview: {
type: Boolean, type: Boolean,
default: true default: true
},
//
sizes: {
type: Array,
default: () => [320, 640, 768, 1024]
},
//
format: {
type: String,
default: 'webp'
},
//
quality: {
type: Number,
default: 80
} }
}) })
const showImage = () => { const showImage = () => {
if (props.preview) { if (props.preview) {
showImagePreview([props.src]); showImagePreview([props.src]);
} }
} }
</script> </script>
<template> <template>
<img <nuxt-img
loading="lazy" loading="lazy"
v-bind="{ ...props, ...$attrs }" v-bind="{ ...props, ...$attrs }"
style="object-fit: cover" style="object-fit: cover"
@click="showImage" @click="showImage"
> :src="src"
:sizes="sizes"
:format="format"
:quality="quality"
placeholder
/>
</template> </template>
<style scoped>
:deep(img) {
width: 100%;
height: 100%;
}
</style>

View File

@ -1,3 +1,3 @@
export const useAppFooterRouteNames= ['home', 'profile'] export const useAppFooterRouteNames= ['index', 'profile']
export const useAppHeaderRouteNames= ['home', 'profile','login'] export const useAppHeaderRouteNames= ['index', 'profile','login']

View File

@ -10,13 +10,12 @@ import {ref} from "vue";
const {fullLive, getAuctionDetail, auctionDetail, itemList, pageRef, liveRef} = goodStore(); const {fullLive, getAuctionDetail, auctionDetail, itemList, pageRef, liveRef} = goodStore();
definePageMeta({ definePageMeta({
layout: 'default', layout: 'default',
title: '主页',
i18n: 'menu.home', i18n: 'menu.home',
}) })
const changeLive = () => { const changeLive = () => {
fullLive.value = true; fullLive.value = true;
}; };
const showBottom = ref(true)
</script> </script>
<template> <template>
@ -73,7 +72,7 @@ const showBottom = ref(true)
.changeLive { .changeLive {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
transition: height 0.5s ease, transform 0.5s ease; transition: height 0.4s ease, transform 0.4s ease;
} }
.changeLive.collapsed { .changeLive.collapsed {

7
app/pages/index.vue Normal file
View File

@ -0,0 +1,7 @@
<script setup>
import Home from './home/index.vue'
</script>
<template>
<Home/>
</template>

View File

@ -1,4 +0,0 @@
:root:root {
--van-primary-color: var(--c-primary);
--van-cell-group-inset-padding: 0;
}

View File

@ -1,14 +0,0 @@
#__nuxt {
margin: 0;
padding: 0;
}
html {
background: var(--van-gray-1);
color-scheme: light;
}
html.dark {
background: #222;
color-scheme: dark;
}

View File

@ -1,4 +0,0 @@
:root {
--c-primary: #3554AF;
--c-primary-active: #3554AF;
}

View File

@ -1,61 +1,58 @@
// 导入环境变量处理库
import dotenv from 'dotenv' import dotenv from 'dotenv'
// 导入 Node.js 进程模块
import process from 'node:process' import process from 'node:process'
// 导入预加载工具函数
import preload from './app/utils/preload' import preload from './app/utils/preload'
// 导入国际化语言配置
import { currentLocales } from './i18n/i18n' import { currentLocales } from './i18n/i18n'
// 设置环境变量文件路径,默认使用 .env.test
const envFile = process.env.ENV_FILE || '.env.test' const envFile = process.env.ENV_FILE || '.env.test'
// 加载环境变量配置
dotenv.config({ path: `./env/${envFile}` }) dotenv.config({ path: `./env/${envFile}` })
// 过滤出以 NUXT_PUBLIC_ 开头的环境变量作为公共配置
const publicConfig = Object.entries(process.env) const publicConfig = Object.entries(process.env)
.filter(([key]) => key.startsWith('NUXT_PUBLIC_')) .filter(([key]) => key.startsWith('NUXT_PUBLIC_'))
.reduce((config, [key, value]) => { .reduce((config, [key, value]) => {
config[key] = value config[key] = value
return config return config
}, {}) }, {})
export default defineNuxtConfig({ export default defineNuxtConfig({
hooks: { // 注册 Nuxt 模块
'pages:extend'(pages) {
const indexPage = pages.findIndex(page => page.path === '/')
if (indexPage !== -1) {
pages.splice(indexPage, 1)
}
pages.push({
name: 'home',
path: '/',
file: '@/pages/home/index.vue'
})
}
},
modules: [ modules: [
'@vant/nuxt', '@nuxt/image', // 图片优化模块
'@unocss/nuxt', '@vant/nuxt', // Vant UI 组件库
'@nuxtjs/color-mode', '@unocss/nuxt', // 原子化 CSS 框架
'@nuxtjs/i18n', '@nuxtjs/i18n', // 国际化模块
], ],
// 运行时配置
runtimeConfig: { runtimeConfig: {
// 私有配置,只有在服务端可用 // 私有配置,只在服务端可用
apiSecret: process.env.NUXT_API_SECRET || 'default_secret', apiSecret: process.env.NUXT_API_SECRET || 'default_secret',
// 公共配置,客户端和服务端都可用 // 公共配置,客户端和服务端都可用
public: publicConfig, public: publicConfig,
}, },
// CSS 配置
css: [ css: [
'@unocss/reset/tailwind.css', '@unocss/reset/tailwind.css', // 重置默认样式
'./app/styles/vars.css',
'./app/styles/global.css',
'./app/styles/default-theme.css',
], ],
// PostCSS 配置
postcss: { postcss: {
plugins: { plugins: {
'autoprefixer': {}, 'autoprefixer': {}, // 自动添加 CSS 前缀
// 移动端适配插件配置
// https://github.com/wswmsword/postcss-mobile-forever
'postcss-mobile-forever': { 'postcss-mobile-forever': {
appSelector: '#__nuxt', appSelector: '#__nuxt', // 根选择器
viewportWidth: 375, viewportWidth: 375, // 设计稿宽度
maxDisplayWidth: 600, maxDisplayWidth: 600, // 最大显示宽度
// devtools excluded exclude: /@nuxt/, // 排除的文件
exclude: /@nuxt/, border: true, // 显示边框
border: true,
rootContainingBlockSelectorList: [ rootContainingBlockSelectorList: [
'van-tabbar', 'van-tabbar',
'van-popup', 'van-popup',
@ -64,89 +61,153 @@ export default defineNuxtConfig({
}, },
}, },
colorMode: { // 国际化配置
classSuffix: '',
preference: 'system',
fallback: 'light',
storageKey: 'nuxt-color-mode',
},
i18n: { i18n: {
locales: currentLocales, locales: currentLocales, // 支持的语言列表
lazy: true, lazy: true, // 懒加载语言包
strategy: 'no_prefix', strategy: 'no_prefix', // URL 策略:不添加语言前缀
detectBrowserLanguage: { detectBrowserLanguage: {
useCookie: true, useCookie: true, // 使用 cookie 存储语言选择
cookieKey: 'i18n_redirected', cookieKey: 'i18n_redirected', // cookie 键名
redirectOn: 'root', redirectOn: 'root', // 仅在根路径重定向
alwaysRedirect: true, alwaysRedirect: true, // 总是重定向
fallbackLocale: 'zh-CN' fallbackLocale: 'zh-CN' // 默认语言
}, },
langDir: 'locales', langDir: 'locales', // 语言文件目录
defaultLocale: 'zh-CN', defaultLocale: 'zh-CN', // 默认语言
vueI18n: './i18n/i18n.config.ts', vueI18n: './i18n/i18n.config.ts', // Vue I18n 配置文件
}, },
// 应用配置
app: { app: {
layoutTransition: { // 布局过渡动画
layoutTransition: {
name: 'layout', name: 'layout',
mode: 'out-in' mode: 'out-in'
}, },
// 头部配置
head: { head: {
// 视口配置
viewport: 'width=device-width,initial-scale=1,viewport-fit=cover', viewport: 'width=device-width,initial-scale=1,viewport-fit=cover',
// 链接配置
link: [ link: [
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' }, { 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 预解析
], ],
// Meta 标签配置
meta: [ meta: [
{ name: 'viewport', content: 'width=device-width, initial-scale=1, viewport-fit=cover,user-scalable=no' }, { name: 'apple-mobile-web-app-capable', content: 'yes' }, // iOS 应用模式
{ name: 'apple-mobile-web-app-capable', content: 'yes' }, { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' }, // iOS 状态栏样式
{ 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: light)', content: '#ffffff' }, { name: 'theme-color', media: '(prefers-color-scheme: dark)', content: '#222222' }, // 深色主题色
{ name: 'theme-color', media: '(prefers-color-scheme: dark)', content: '#222222' }, { name: 'description', content: '你的网站描述' }, // SEO 描述
{ 'http-equiv': 'x-dns-prefetch-control', content: 'on' }, // DNS 预解析控制
], ],
// 脚本配置
script: [ script: [
{ innerHTML: preload(), type: 'text/javascript', tagPosition: 'head' }, { 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'
}
], ],
}, },
}, },
// Vite 构建配置
vite: { vite: {
build: { build: {
target: 'esnext', 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
}
}
}, },
// 依赖优化配置
optimizeDeps: { optimizeDeps: {
include: [ include: [
'@intlify/core-base', '@intlify/core-base', // I18n 核心
'@intlify/shared', '@intlify/shared', // I18n 共享库
'is-https', 'is-https', // HTTPS 检测
'vant', // Vant UI
'@vant/use', // Vant Hooks
'@vueuse/core', // VueUse 工具集
], ],
}, },
}, },
// 实验性功能
experimental: { experimental: {
typedPages: true, typedPages: true, // 启用页面类型
}, },
// 开发工具
devtools: { devtools: {
enabled: true, enabled: true, // 启用开发工具
}, },
// TypeScript 配置
typescript: { typescript: {
shim: false, shim: false, // 禁用 shim
}, },
// 功能特性配置
features: { features: {
// For UnoCSS inlineStyles: false, // 禁用内联样式
inlineStyles: false,
}, },
// 未来特性配置
future: { future: {
compatibilityVersion: 4, compatibilityVersion: 4, // 兼容性版本
}, },
// 指定 Nuxt 应用程序的兼容性日期,确保应用程序在未来的 Nuxt 版本中保持稳定性
compatibilityDate: '2025-01-09', // Nuxt 兼容性日期
compatibilityDate: '2025-01-09', // 确保未来版本兼容性
// 开发服务器配置
devServer: { devServer: {
host: '0.0.0.0', // Set the host to 'localhost' host: '0.0.0.0', // 主机地址
port: 3000, // Set the port to 3000 or any other port you prefer port: 3000, // 端口号
}, },
// 图片优化配置
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 // 模糊加载效果
}
}) })

View File

@ -17,7 +17,6 @@
"start": "cross-env ENV_FILE=.env.prod nuxt start" "start": "cross-env ENV_FILE=.env.prod nuxt start"
}, },
"dependencies": { "dependencies": {
"@nuxtjs/color-mode": "^3.5.2",
"@nuxtjs/i18n": "^9.1.1", "@nuxtjs/i18n": "^9.1.1",
"@vueuse/core": "^12.4.0", "@vueuse/core": "^12.4.0",
"@yeger/vue-masonry-wall": "^5.0.17", "@yeger/vue-masonry-wall": "^5.0.17",
@ -33,6 +32,7 @@
}, },
"devDependencies": { "devDependencies": {
"@iconify-json/carbon": "^1.2.5", "@iconify-json/carbon": "^1.2.5",
"@nuxt/image": "^1.9.0",
"@unocss/nuxt": "0.65.2", "@unocss/nuxt": "0.65.2",
"@unocss/preset-rem-to-px": "0.65.2", "@unocss/preset-rem-to-px": "0.65.2",
"@vant/nuxt": "^1.0.6", "@vant/nuxt": "^1.0.6",

File diff suppressed because it is too large Load Diff