Naive UI 学习指南 - Vue3 初学者完全教程
什么是 Naive UI?
Naive UI 是一个基于 Vue3 的 UI 组件库,就像乐高积木一样,提供了现成的"积木块"(按钮、表单、表格等),让你可以快速搭建漂亮的网页界面。
为什么选择 Naive UI?
- 🎨 颜值高:设计现代、美观
- ⚡ 性能好:按需加载,速度快
- 📱 响应式:适配各种设备
- 🌍 功能全:组件丰富,满足大部分需求
注意 : 相关代码已经过实测验证 。如果遇到useMessage
问题,解决办法请参见 Vue 3 + Naive UI 调用useMessage的方法(在Naive UI 2.42.0实测有效)在 Naiv - 掘金
学习路径规划
学习路径:循序渐进
第1步:环境搭建 → 安装配置
第2步:基础组件 → 按钮、输入框等
第3步:布局组件 → 栅格、卡片等
第4步:表单组件 → 表单验证、提交等
第5步:数据展示 → 表格、列表等
第6步:反馈组件 → 弹窗、消息等
第7步:高级功能 → 主题、国际化等
第1步:环境搭建和安装
1. 创建 Vue3 项目
bash
# 安装 Vue CLI(如果还没安装)
npm install -g @vue/cli
# 创建新项目
vue create my-naive-ui-app
# 进入项目目录
cd my-naive-ui-app
# 安装 Naive UI
npm install naive-ui
2. 基础配置
javascript
// main.js - 项目入口文件
import { createApp } from 'vue'
import App from './App.vue'
// 导入 Naive UI
import naive from 'naive-ui'
const app = createApp(App)
app.use(naive) // 使用 Naive UI
app.mount('#app')
第2步:基础组件学习
1. 按钮组件 (n-button)
vue
<!-- BasicButtons.vue -->
<template>
<div class="button-demo">
<h2>按钮组件演示</h2>
<!-- 基础按钮 -->
<n-button>默认按钮</n-button>
<n-button type="primary">主要按钮</n-button>
<n-button type="success">成功按钮</n-button>
<n-button type="warning">警告按钮</n-button>
<n-button type="error">错误按钮</n-button>
<!-- 不同尺寸 -->
<n-button size="small">小按钮</n-button>
<n-button size="medium">中按钮</n-button>
<n-button size="large">大按钮</n-button>
<!-- 带图标的按钮 -->
<n-button>
<template #icon>
<n-icon>
<Search />
</n-icon>
</template>
搜索
</n-button>
<!-- 禁用状态 -->
<n-button disabled>禁用按钮</n-button>
<!-- 事件处理 -->
<n-button @click="handleClick">点击我</n-button>
</div>
</template>
<script setup>
import { Search } from '@vicons/ionicons5'
import { useMessage } from 'naive-ui'
const message = useMessage()
const handleClick = () => {
message.success('按钮被点击了!')
}
</script>
<style scoped>
.button-demo {
padding: 20px;
}
.n-button {
margin: 5px;
}
</style>
2. 输入框组件 (n-input)
vue
<!-- BasicInputs.vue -->
<template>
<div class="input-demo">
<h2>输入框组件演示</h2>
<!-- 基础输入框 -->
<n-input v-model:value="basicInput" placeholder="请输入内容" />
<!-- 带标签的输入框 -->
<n-input v-model:value="labeledInput" placeholder="用户名">
<template #prefix>
<n-icon><Person /></n-icon>
</template>
</n-input>
<!-- 密码输入框 -->
<n-input
v-model:value="password"
type="password"
show-password-on="click"
placeholder="请输入密码"
/>
<!-- 多行文本 -->
<n-input
v-model:value="textarea"
type="textarea"
placeholder="请输入详细描述"
:autosize="{ minRows: 3, maxRows: 5 }"
/>
<!-- 禁用状态 -->
<n-input v-model:value="disabledInput" disabled placeholder="禁用输入框" />
<!-- 清除按钮 -->
<n-input
v-model:value="clearableInput"
clearable
placeholder="可清除的输入框"
/>
<!-- 显示当前值 -->
<div class="current-values">
<p>基础输入框值:{{ basicInput }}</p>
<p>密码输入框值:{{ password }}</p>
<p>多行文本值:{{ textarea }}</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Person } from '@vicons/ionicons5'
// 定义响应式数据
const basicInput = ref('')
const labeledInput = ref('')
const password = ref('')
const textarea = ref('')
const disabledInput = ref('这是禁用的')
const clearableInput = ref('')
</script>
<style scoped>
.input-demo {
padding: 20px;
}
.n-input {
margin-bottom: 15px;
max-width: 300px;
}
.current-values {
margin-top: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 4px;
}
</style>
第3步:布局组件学习
1. 栅格系统 (n-grid, n-gi)
vue
<!-- GridLayout.vue -->
<template>
<div class="grid-demo">
<h2>栅格布局演示</h2>
<!-- 基础栅格 -->
<n-grid :cols="3" :x-gap="12" :y-gap="12">
<n-gi>
<div class="grid-item">列1</div>
</n-gi>
<n-gi>
<div class="grid-item">列2</div>
</n-gi>
<n-gi>
<div class="grid-item">列3</div>
</n-gi>
</n-grid>
<!-- 响应式栅格 -->
<n-grid :x-gap="12" :y-gap="12" :cols="4">
<n-gi :span="4">
<div class="grid-item full-width">占4列(100%)</div>
</n-gi>
<n-gi :span="1">
<div class="grid-item">1/4</div>
</n-gi>
<n-gi :span="1">
<div class="grid-item">1/4</div>
</n-gi>
<n-gi :span="2">
<div class="grid-item">2/4</div>
</n-gi>
</n-grid>
<!-- 自适应栅格 -->
<n-grid :x-gap="12" :y-gap="12" :cols="3">
<n-gi>
<div class="grid-item">自适应1</div>
</n-gi>
<n-gi :span="2">
<div class="grid-item">自适应2(占2倍宽)</div>
</n-gi>
</n-grid>
</div>
</template>
<script setup>
</script>
<style scoped>
.grid-demo {
padding: 20px;
}
.grid-item {
background: #e6f7ff;
border: 1px solid #91d5ff;
padding: 20px;
text-align: center;
border-radius: 4px;
}
.full-width {
background: #fffbe6;
border-color: #ffe58f;
}
</style>
2. 卡片组件 (n-card)
vue
<!-- CardDemo.vue -->
<template>
<div class="card-demo">
<h2>卡片组件演示</h2>
<!-- 基础卡片 -->
<n-card title="基础卡片">
<p>这是卡片的内容区域</p>
</n-card>
<!-- 带操作的卡片 -->
<n-card
title="带操作的卡片"
:bordered="false"
size="small"
>
<template #header-extra>
<n-button text>更多</n-button>
</template>
<p>卡片内容可以很丰富</p>
<template #action>
<n-space>
<n-button size="small">操作1</n-button>
<n-button size="small" type="primary">操作2</n-button>
</n-space>
</template>
</n-card>
<!-- 带图片的卡片 -->
<n-card
title="产品卡片"
hoverable
>
<template #cover>
<img
src="https://picsum.photos/300/200"
alt="产品图片"
style="width: 100%"
>
</template>
<n-ellipsis style="margin-bottom: 12px">
这是一个很棒的产品,具有很多优秀的特性...
</n-ellipsis>
<div style="text-align: right">
<n-button type="primary">购买</n-button>
</div>
</n-card>
</div>
</template>
<script setup>
import { NSpace } from 'naive-ui'
</script>
<style scoped>
.card-demo {
padding: 20px;
}
.n-card {
margin-bottom: 20px;
max-width: 400px;
}
</style>
第4步:表单组件学习
完整表单示例
vue
<!-- UserForm.vue -->
<template>
<div class="form-demo">
<h2>用户注册表单</h2>
<n-form
:model="formValue"
:rules="rules"
ref="formRef"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<!-- 用户名 -->
<n-form-item label="用户名" path="username">
<n-input
v-model:value="formValue.username"
placeholder="请输入用户名"
@keydown.enter.prevent
/>
</n-form-item>
<!-- 邮箱 -->
<n-form-item label="邮箱" path="email">
<n-input
v-model:value="formValue.email"
placeholder="请输入邮箱"
/>
</n-form-item>
<!-- 密码 -->
<n-form-item label="密码" path="password">
<n-input
v-model:value="formValue.password"
type="password"
placeholder="请输入密码"
/>
</n-form-item>
<!-- 确认密码 -->
<n-form-item label="确认密码" path="confirmPassword">
<n-input
v-model:value="formValue.confirmPassword"
type="password"
placeholder="请再次输入密码"
/>
</n-form-item>
<!-- 性别 -->
<n-form-item label="性别" path="gender">
<n-radio-group v-model:value="formValue.gender">
<n-space>
<n-radio value="male">男</n-radio>
<n-radio value="female">女</n-radio>
</n-space>
</n-radio-group>
</n-form-item>
<!-- 兴趣爱好 -->
<n-form-item label="兴趣爱好" path="hobbies">
<n-checkbox-group v-model:value="formValue.hobbies">
<n-space>
<n-checkbox value="reading">阅读</n-checkbox>
<n-checkbox value="music">音乐</n-checkbox>
<n-checkbox value="sports">运动</n-checkbox>
<n-checkbox value="travel">旅行</n-checkbox>
</n-space>
</n-checkbox-group>
</n-form-item>
<!-- 生日 -->
<n-form-item label="生日" path="birthday">
<n-date-picker
v-model:value="formValue.birthday"
type="date"
clearable
/>
</n-form-item>
<!-- 个人简介 -->
<n-form-item label="个人简介" path="bio">
<n-input
v-model:value="formValue.bio"
type="textarea"
placeholder="请简单介绍一下自己"
:autosize="{ minRows: 3 }"
/>
</n-form-item>
<!-- 同意协议 -->
<n-form-item path="agreement">
<n-checkbox v-model:checked="formValue.agreement">
我已阅读并同意用户协议
</n-checkbox>
</n-form-item>
<!-- 提交按钮 -->
<n-form-item>
<n-space>
<n-button type="primary" @click="handleSubmit">
注册
</n-button>
<n-button @click="handleReset">
重置
</n-button>
</n-space>
</n-form-item>
</n-form>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { useMessage } from 'naive-ui'
const message = useMessage()
const formRef = ref(null)
// 表单数据
const formValue = reactive({
username: '',
email: '',
password: '',
confirmPassword: '',
gender: null,
hobbies: [],
birthday: null,
bio: '',
agreement: false
})
// 表单验证规则
const rules = {
username: {
required: true,
message: '请输入用户名',
trigger: 'blur'
},
email: [
{
required: true,
message: '请输入邮箱',
trigger: 'blur'
},
{
type: 'email',
message: '请输入正确的邮箱格式',
trigger: ['input', 'blur']
}
],
password: {
required: true,
message: '请输入密码',
trigger: 'blur'
},
confirmPassword: {
required: true,
validator: (rule, value) => {
if (!value) {
return new Error('请再次输入密码')
} else if (value !== formValue.password) {
return new Error('两次输入的密码不一致')
}
return true
},
trigger: ['blur', 'password-input']
},
gender: {
required: true,
message: '请选择性别',
trigger: 'change'
},
agreement: {
required: true,
validator: (rule, value) => {
if (!value) {
return new Error('请同意用户协议')
}
return true
},
trigger: 'change'
}
}
// 提交表单
const handleSubmit = (e) => {
e.preventDefault()
formRef.value?.validate((errors) => {
if (!errors) {
message.success('注册成功!')
console.log('表单数据:', formValue)
} else {
message.error('请检查表单信息')
}
})
}
// 重置表单
const handleReset = () => {
Object.assign(formValue, {
username: '',
email: '',
password: '',
confirmPassword: '',
gender: null,
hobbies: [],
birthday: null,
bio: '',
agreement: false
})
message.info('表单已重置')
}
</script>
<style scoped>
.form-demo {
padding: 20px;
max-width: 600px;
margin: 0 auto;
}
</style>
第5步:数据展示组件学习
1. 表格组件 (n-data-table)
vue
<!-- DataTableDemo.vue -->
<template>
<div class="table-demo">
<h2>数据表格演示</h2>
<n-data-table
:columns="columns"
:data="tableData"
:pagination="pagination"
:bordered="true"
striped
/>
</div>
</template>
<script setup>
import { h } from 'vue'
import { NButton, NSpace, useMessage } from 'naive-ui'
const message = useMessage()
// 表格列配置
const columns = [
{
title: 'ID',
key: 'id',
width: 100
},
{
title: '姓名',
key: 'name',
width: 150
},
{
title: '年龄',
key: 'age',
width: 100
},
{
title: '邮箱',
key: 'email',
ellipsis: true
},
{
title: '状态',
key: 'status',
render(row) {
return h(
'span',
{
style: {
color: row.status === 'active' ? 'green' : 'red'
}
},
row.status === 'active' ? '活跃' : '禁用'
)
}
},
{
title: '操作',
key: 'actions',
width: 200,
render(row) {
return h(NSpace, null, {
default: () => [
h(
NButton,
{
size: 'small',
onClick: () => handleEdit(row)
},
{ default: () => '编辑' }
),
h(
NButton,
{
size: 'small',
type: 'error',
onClick: () => handleDelete(row)
},
{ default: () => '删除' }
)
]
})
}
}
]
// 表格数据
const tableData = [
{
id: 1,
name: '张三',
age: 25,
email: 'zhangsan@example.com',
status: 'active'
},
{
id: 2,
name: '李四',
age: 30,
email: 'lisi@example.com',
status: 'active'
},
{
id: 3,
name: '王五',
age: 28,
email: 'wangwu@example.com',
status: 'inactive'
},
{
id: 4,
name: '赵六',
age: 35,
email: 'zhaoliu@example.com',
status: 'active'
}
]
// 分页配置
const pagination = {
pageSize: 10
}
// 编辑操作
const handleEdit = (row) => {
message.info(`编辑用户:${row.name}`)
}
// 删除操作
const handleDelete = (row) => {
message.warning(`删除用户:${row.name}`)
}
</script>
<style scoped>
.table-demo {
padding: 20px;
}
</style>
2. 列表组件 (n-list)
vue
<!-- ListDemo.vue -->
<template>
<div class="list-demo">
<h2>列表组件演示</h2>
<n-list bordered>
<template #header>
<h3>最新文章</h3>
</template>
<n-list-item v-for="article in articles" :key="article.id">
<n-thing :title="article.title" :description="article.author">
<template #avatar>
<n-avatar>
<n-icon>
<DocumentText />
</n-icon>
</n-avatar>
</template>
<template #header-extra>
<n-tag :type="article.tagType">
{{ article.category }}
</n-tag>
</template>
<template #description>
<span>{{ article.author }} · {{ article.date }}</span>
</template>
<div style="margin-top: 10px">
{{ article.summary }}
</div>
<template #action>
<n-space>
<n-button text>阅读更多</n-button>
<n-button text type="primary">点赞 {{ article.likes }}</n-button>
</n-space>
</template>
</n-thing>
</n-list-item>
<template #footer>
<div style="text-align: center; padding: 12px">
<n-button>加载更多</n-button>
</div>
</template>
</n-list>
</div>
</template>
<script setup>
import { DocumentText } from '@vicons/ionicons5'
const articles = [
{
id: 1,
title: 'Vue3 入门指南',
author: '张三',
date: '2024-01-15',
category: '前端',
tagType: 'success',
summary: 'Vue3 是目前最流行的前端框架之一,本文将带你快速入门 Vue3 的核心概念...',
likes: 128
},
{
id: 2,
title: 'CSS 布局技巧',
author: '李四',
date: '2024-01-12',
category: 'CSS',
tagType: 'warning',
summary: '掌握 CSS 布局是前端开发的基础,本文介绍了 Flexbox 和 Grid 等现代布局技术...',
likes: 95
},
{
id: 3,
title: 'JavaScript 异步编程',
author: '王五',
date: '2024-01-10',
category: 'JavaScript',
tagType: 'error',
summary: '异步编程是 JavaScript 的核心特性,本文详细讲解了 Promise、async/await 等概念...',
likes: 203
}
]
</script>
<style scoped>
.list-demo {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
</style>
第6步:反馈组件学习
1. 消息提示 (useMessage)
vue
<!-- MessageDemo.vue -->
<template>
<div class="message-demo">
<h2>消息提示演示</h2>
<n-space vertical>
<n-button @click="showSuccess">成功消息</n-button>
<n-button @click="showError">错误消息</n-button>
<n-button @click="showWarning">警告消息</n-button>
<n-button @click="showInfo">信息消息</n-button>
<n-button @click="showLoading">加载消息</n-button>
</n-space>
</div>
</template>
<script setup>
import { useMessage } from 'naive-ui'
const message = useMessage()
const showSuccess = () => {
message.success('操作成功!')
}
const showError = () => {
message.error('操作失败,请重试!')
}
const showWarning = () => {
message.warning('请注意,这是一条警告信息!')
}
const showInfo = () => {
message.info('这是一条普通信息提示!')
}
const showLoading = () => {
const msg = message.loading('正在加载中...', {
duration: 0
})
// 3秒后关闭
setTimeout(() => {
msg.destroy()
message.success('加载完成!')
}, 3000)
}
</script>
<style scoped>
.message-demo {
padding: 20px;
}
.n-button {
margin: 5px 0;
}
</style>
2. 弹窗组件 (n-modal)
vue
<!-- ModalDemo.vue -->
<template>
<div class="modal-demo">
<h2>弹窗组件演示</h2>
<n-space vertical>
<n-button @click="showBasicModal = true">基础弹窗</n-button>
<n-button @click="showConfirmModal = true">确认弹窗</n-button>
<n-button @click="showCustomModal = true">自定义弹窗</n-button>
</n-space>
<!-- 基础弹窗 -->
<n-modal v-model:show="showBasicModal" preset="dialog" title="提示">
<p>这是一个基础的弹窗示例</p>
</n-modal>
<!-- 确认弹窗 -->
<n-modal
v-model:show="showConfirmModal"
preset="dialog"
title="确认操作"
positive-text="确认"
negative-text="取消"
@positive-click="handleConfirm"
>
<p>确定要执行此操作吗?</p>
</n-modal>
<!-- 自定义弹窗 -->
<n-modal v-model:show="showCustomModal">
<n-card
style="width: 600px"
title="用户信息"
:bordered="false"
size="huge"
role="dialog"
aria-modal="true"
>
<n-form :model="userInfo" label-placement="left" label-width="80">
<n-form-item label="姓名">
<n-input v-model:value="userInfo.name" />
</n-form-item>
<n-form-item label="邮箱">
<n-input v-model:value="userInfo.email" />
</n-form-item>
<n-form-item label="电话">
<n-input v-model:value="userInfo.phone" />
</n-form-item>
</n-form>
<template #footer>
<n-space>
<n-button @click="showCustomModal = false">取消</n-button>
<n-button type="primary" @click="saveUserInfo">保存</n-button>
</n-space>
</template>
</n-card>
</n-modal>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { useMessage } from 'naive-ui'
const message = useMessage()
// 弹窗显示状态
const showBasicModal = ref(false)
const showConfirmModal = ref(false)
const showCustomModal = ref(false)
// 用户信息
const userInfo = reactive({
name: '',
email: '',
phone: ''
})
// 确认操作
const handleConfirm = () => {
message.success('操作已确认!')
}
// 保存用户信息
const saveUserInfo = () => {
message.success('用户信息已保存!')
showCustomModal.value = false
}
</script>
<style scoped>
.modal-demo {
padding: 20px;
}
.n-button {
margin: 5px 0;
}
</style>
第7步:完整项目实战
用户管理系统
vue
<!-- UserManagement.vue -->
<template>
<div class="user-management">
<n-card title="用户管理系统">
<!-- 搜索和操作区域 -->
<div class="toolbar">
<n-space>
<n-input
v-model:value="searchKeyword"
placeholder="搜索用户名或邮箱"
clearable
>
<template #prefix>
<n-icon><Search /></n-icon>
</template>
</n-input>
<n-button type="primary" @click="showAddModal = true">
<template #icon>
<n-icon><Add /></n-icon>
</template>
添加用户
</n-button>
</n-space>
</div>
<!-- 用户表格 -->
<n-data-table
:columns="columns"
:data="filteredUsers"
:pagination="pagination"
:bordered="true"
striped
:loading="loading"
/>
</n-card>
<!-- 添加用户弹窗 -->
<n-modal v-model:show="showAddModal">
<n-card
style="width: 600px"
title="添加用户"
:bordered="false"
size="huge"
>
<UserForm
ref="userFormRef"
@submit="handleAddUser"
@cancel="showAddModal = false"
/>
</n-card>
</n-modal>
</div>
</template>
<script setup>
import { ref, computed, onMounted, h } from 'vue' // 添加 h 的导入
import { useMessage } from 'naive-ui'
import { Search, Add } from '@vicons/ionicons5'
import UserForm from './UserForm.vue'
const message = useMessage()
// 响应式数据
const searchKeyword = ref('')
const showAddModal = ref(false)
const loading = ref(false)
const users = ref([])
const userFormRef = ref(null)
// 模拟用户数据
const mockUsers = [
{ id: 1, name: '张三', email: 'zhangsan@example.com', role: '管理员', status: 'active', createTime: '2024-01-01' },
{ id: 2, name: '李四', email: 'lisi@example.com', role: '用户', status: 'active', createTime: '2024-01-02' },
{ id: 3, name: '王五', email: 'wangwu@example.com', role: '用户', status: 'inactive', createTime: '2024-01-03' }
]
// 表格列配置
const columns = [
{ title: 'ID', key: 'id', width: 80 },
{ title: '姓名', key: 'name', width: 120 },
{ title: '邮箱', key: 'email', ellipsis: true },
{
title: '角色',
key: 'role',
render(row) {
return row.role === '管理员'
? h('n-tag', { type: 'error' }, '管理员')
: h('n-tag', { type: 'default' }, '用户')
}
},
{
title: '状态',
key: 'status',
render(row) {
return row.status === 'active'
? h('n-tag', { type: 'success' }, '活跃')
: h('n-tag', { type: 'warning' }, '禁用')
}
},
{ title: '创建时间', key: 'createTime', width: 120 },
{
title: '操作',
key: 'actions',
width: 150,
render(row) {
return h('n-space', { size: 'small' }, [
h('n-button', {
size: 'small',
type: 'primary',
onClick: () => editUser(row)
}, '编辑'),
h('n-button', {
size: 'small',
type: 'error',
onClick: () => deleteUser(row)
}, '删除')
])
}
}
]
// 分页配置
const pagination = {
pageSize: 10
}
// 过滤用户数据
const filteredUsers = computed(() => {
if (!searchKeyword.value) return users.value
const keyword = searchKeyword.value.toLowerCase()
return users.value.filter(user =>
user.name.toLowerCase().includes(keyword) ||
user.email.toLowerCase().includes(keyword)
)
})
// 加载用户数据
const loadUsers = async () => {
loading.value = true
try {
// 模拟 API 调用
await new Promise(resolve => setTimeout(resolve, 1000))
users.value = [...mockUsers]
} catch (error) {
message.error('加载用户数据失败')
} finally {
loading.value = false
}
}
// 添加用户
const handleAddUser = (userData) => {
const newUser = {
id: users.value.length + 1,
...userData,
status: 'active',
createTime: new Date().toISOString().split('T')[0]
}
users.value.push(newUser)
showAddModal.value = false
message.success('用户添加成功')
}
// 编辑用户
const editUser = (user) => {
message.info(`编辑用户:${user.name}`)
}
// 删除用户
const deleteUser = (user) => {
window.$dialog.warning({
title: '确认删除',
content: `确定要删除用户 ${user.name} 吗?`,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
users.value = users.value.filter(u => u.id !== user.id)
message.success('用户删除成功')
}
})
}
// 组件挂载时加载数据
onMounted(() => {
loadUsers()
})
</script>
<style scoped>
.user-management {
padding: 20px;
}
.toolbar {
margin-bottom: 20px;
}
</style>
学习建议和最佳实践
1. 学习顺序建议
scss
第1周:基础组件 (按钮、输入框、图标)
第2周:布局组件 (栅格、卡片、空间)
第3周:表单组件 (表单、验证、选择器)
第4周:数据展示 (表格、列表、树)
第5周:反馈组件 (消息、弹窗、加载)
第6周:导航组件 (菜单、标签页、面包屑)
第7周:综合项目实战
2. 实践建议
javascript
// 1. 按需导入(推荐)
import { NButton, NInput } from 'naive-ui'
// 2. 全局导入(开发时方便)
import naive from 'naive-ui'
// 3. 主题定制
// 在 main.js 中
import { createTheme } from 'naive-ui'
const theme = createTheme({
common: {
primaryColor: '#18a058'
}
})
// 4. 国际化
import { zhCN } from 'naive-ui'
app.use(naive, {
locale: zhCN
})
3. 常见问题解决
vue
<!-- 问题1:组件样式不生效 -->
<!-- 解决:确保正确引入样式 -->
<script setup>
// 确保导入了组件
import { NButton } from 'naive-ui'
</script>
<!-- 问题2:图标不显示 -->
<!-- 解决:安装图标库 -->
<!-- npm install @vicons/ionicons5 -->
<!-- 问题3:表单验证不工作 -->
<!-- 解决:确保正确设置 rules 和 path -->
<n-form :model="model" :rules="rules">
<n-form-item label="用户名" path="username">
<n-input v-model:value="model.username" />
</n-form-item>
</n-form>
通过这个循序渐进的学习路径,你可以从基础到高级逐步掌握 Naive UI 的使用方法。记住:多练习、多实践是最好的学习方式!