一、为什么选择 Vue3 + Naive UI?
广告平台项目需要同时支持 PC 和移动端管理后台,并且对主题定制、组件可用性要求高。
选择 Vue3 是为了更好的响应式能力和 Composition API;选择 Naive UI 则因为它:
- 全量 TypeScript 支持,利于团队工程化
- 支持暗黑模式、主题变量
- 组件风格现代,覆盖中后台常用场景
二、适配策略:一套代码适应多端布局
Naive UI 官方并不提供响应式布局方案,因此我采用以下策略:
✦ 使用 CSS Grid/Flex 配合媒体查询
.container {
display: grid;
grid-template-columns: 1fr 3fr;
@media screen and (max-width: 768px) {
grid-template-columns: 1fr;
}
}
✦ 结合 useWindowSize() 实现响应式逻辑判断
import { useWindowSize } from '@vueuse/core'
const { width } = useWindowSize()
const isMobile = computed(() => width.value < 768)
用于控制导航栏展开、操作区域折叠等 UI 行为。
✦ 表格适配小屏幕
小屏时切换为卡片展示:
<n-data-table v-if="!isMobile" ... />
<n-card v-else v-for="item in data" :key="item.id">
<div>计划名称:{{ item.name }}</div>
<div>投放状态:{{ item.status }}</div>
</n-card>
三、Naive UI 主题定制实战
统一品牌色 + 暗黑模式支持:
import { darkTheme, useOsTheme } from 'naive-ui'
const osTheme = useOsTheme()
const isDark = computed(() => osTheme.value === 'dark')
const themeOverrides = {
common: {
primaryColor: '#fa541c'
}
}
在 App.vue 中统一挂载:
<n-config-provider :theme="isDark ? darkTheme : null" :theme-overrides="themeOverrides">
<router-view />
</n-config-provider>
四、Naive UI 的组件使用亮点与坑点
✅ 亮点:
n-data-table自带排序、过滤、分页功能n-form与n-form-item校验体验优于 ant-designn-modal支持异步关闭、嵌套弹窗逻辑简洁
⚠️ 坑点:
- 表格使用
row-key必须小心对象变引用后丢失响应 n-form在 slot 中动态渲染组件时,路径匹配容易失效n-select下拉项如果是复杂对象,label-field/value-field必须手动设置
示例修复:
<n-select
v-model:value="value"
:options="options"
label-field="label"
value-field="id"
/>
五、组件复用策略
结合上一节提到的组件抽象,Naive UI 在高度组合化的设计下非常利于封装:
表单字段 schema 封装
const adFormSchema = [
{
label: '计划名称',
field: 'name',
component: 'n-input',
rules: [{ required: true, message: '请输入名称' }]
},
{
label: '预算',
field: 'budget',
component: 'n-input-number',
props: { min: 0 }
}
]
表格 column 封装
const adTableColumns = [
{ title: '计划名称', key: 'name' },
{
title: '状态',
key: 'status',
render(row) {
return h(NTag, { type: row.status === 'on' ? 'success' : 'error' }, { default: () => row.status })
}
}
]
六、适配过程中遇到的真实问题与解决
1. 小屏切换时组件尺寸不合理
原因是 Naive 默认 spacing 和 font-size 偏大,需手动覆盖
const themeOverrides = {
common: {
fontSizeSmall: '12px',
heightSmall: '28px'
}
}
2. 暗黑模式切换后样式未即时刷新
使用 nextTick() 强制触发刷新
watch(isDark, () => {
nextTick(() => {
// 强制刷新局部组件样式
})
})
3. 表单多级嵌套动态渲染校验失效
避免嵌套 slot 中写 form-item,改为显式 flat schema 定义
七、总结
Vue3 + Naive UI 的组合适用于追求工程效率 + UI 统一风格的中后台平台。
多端适配的关键是:
- 宽度响应式策略明确
- 样式约定统一
- 组件行为可控
Naive UI 的灵活性在于它没做太多“约束”,这让我们能自由组合抽象组件,踩坑虽有,但一旦封装完毕,上层业务开发飞快。