Naive UI 学习指南 - Vue3 初学者完全教程

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 的使用方法。记住:多练习、多实践是最好的学习方式

相关推荐
东风西巷7 分钟前
Rubick:基于Electron的开源桌面效率工具箱
前端·javascript·electron·软件需求
探码科技38 分钟前
AI知识管理软件推荐:九大解决方案与企业应用
前端·ruby
编程小黑马40 分钟前
解决flutter 在控制器如controller 无法直接访问私有类方法的问题
前端
unfetteredman1 小时前
Error: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found
前端·javascript·vite
云存储小精灵1 小时前
Dify x 腾讯云 COS MCP:自然语言解锁智能数据处理,零代码构建 AI 新世界
前端·开源
山间板栗1 小时前
微信小程序环境变量设置方案
前端
电商API大数据接口开发Cris1 小时前
Java Spring Boot 集成淘宝 SDK:实现稳定可靠的商品信息查询服务
前端·数据挖掘·api
pepedd8641 小时前
LangChain:大模型开发框架的全方位解析与实践
前端·llm·trae
HANK2 小时前
KLineChart 绘制教程
前端·vue.js
Jerry2 小时前
Compose 利用工具加快开发速度
前端