前言

        Vue3 作为当前前端主流框架,其生态完善度直接决定开发效率和项目质量。在实际开发中,UI 组件库 是页面搭建的基础,表单验证 是交互逻辑的核心,这两个模块也是新手最易踩坑、进阶开发者需优化的关键环节。

        本文从实战落地角度,系统讲解 Vue3 生态中最主流的两款 UI 组件库(Element Plus、Ant Design Vue)的安装、使用与性能优化,以及两种表单验证方案(Element Plus 内置验证、VeeValidate 高级验证)的核心用法与场景选型。内容覆盖基础配置、进阶技巧、踩坑解决方案,既适合 Vue3 新手快速上手,也能为中大型项目提供技术选型参考。

一、Vue3 主流 UI 组件库实战(Element Plus & Ant Design Vue)

1.1 为什么选择这两款 UI 组件库?

        在 Vue3 生态中,Element Plus 和 Ant Design Vue 是使用率最高的两款企业级 UI 组件库,核心优势对比如下:

注:两款组件库均基于 Vue3+TS 开发,支持按需引入、自定义主题,是生产环境的首选,而非小众组件库(如 Naive UI、Vuetify)的「尝鲜式」选择。

1.2 Element Plus:安装与核心使用技巧

1.2.1 环境准备与安装

前置条件:已初始化 Vue3 项目(推荐 Vite+TS),Node 版本≥14.18.0。

安装命令(支持 npm/yarn/pnpm,推荐 pnpm):

# npm
npm install element-plus --save

# yarn
yarn add element-plus

# pnpm(推荐,体积更小、速度更快)
pnpm add element-plus
1.2.2 全局引入 vs 按需引入(性能优化关键)

全局引入(适合快速开发 / 小型项目):优点:配置简单,无需逐个引入组件;缺点:打包体积大,首屏加载慢。

main.ts中配置:

import { createApp } from 'vue'
import App from './App.vue'
// 全局引入Element Plus
import ElementPlus from 'element-plus'
// 引入全部样式
import 'element-plus/dist/index.css'

const app = createApp(App)
// 挂载到Vue实例
app.use(ElementPlus)
app.mount('#app')

按需引入(生产环境首选):优点:只打包使用的组件,体积减少 60%+;缺点:需额外配置插件。

步骤 1:安装按需引入插件

pnpm add unplugin-vue-components unplugin-auto-import -D

步骤 2:修改vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入Element Plus按需引入插件
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    vue(),
    // 自动导入Element Plus的API
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    // 自动导入Element Plus组件
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
})

踩坑提示:按需引入后若样式丢失,需检查vite.config.ts是否配置正确,或手动引入单个组件的样式(如import 'element-plus/es/components/button/style/css')。

1.2.3 基础组件实战(按钮 / 表格 / 表单容器)

1)按钮组件(最基础,演示属性配置):

<template>
  <div class="button-demo">
    <!-- 基础按钮 -->
    <el-button>默认按钮</el-button>
    <!-- 类型按钮 -->
    <el-button type="primary">主要按钮</el-button>
    <el-button type="success">成功按钮</el-button>
    <!-- 禁用状态 -->
    <el-button type="danger" disabled>禁用按钮</el-button>
    <!-- 图标按钮 -->
    <el-button type="warning" icon="el-icon-search">搜索</el-button>
  </div>
</template>

<style scoped>
.button-demo {
  gap: 10px;
  display: flex;
}
</style>

2)表格组件(中后台核心,演示数据绑定 / 列配置):

<template>
  <el-table :data="tableData" border style="width: 100%">
    <!-- 普通列 -->
    <el-table-column prop="name" label="姓名" width="180" />
    <!-- 自定义列(如状态标签) -->
    <el-table-column prop="status" label="状态">
      <template #default="scope">
        <el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'">
          {{ scope.row.status === 'active' ? '活跃' : '禁用' }}
        </el-tag>
      </template>
    </el-table-column>
    <!-- 操作列 -->
    <el-table-column label="操作">
      <template #default="scope">
        <el-button size="small" type="primary" @click="handleEdit(scope.row)">编辑</el-button>
        <el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

<script setup lang="ts">
// 定义表格数据类型
interface TableRow {
  name: string;
  status: string;
  id: number;
}

// 模拟表格数据
const tableData: TableRow[] = [
  { id: 1, name: '张三', status: 'active' },
  { id: 2, name: '李四', status: 'disabled' },
  { id: 3, name: '王五', status: 'active' },
];

// 编辑事件
const handleEdit = (row: TableRow) => {
  console.log('编辑:', row);
};

// 删除事件
const handleDelete = (row: TableRow) => {
  console.log('删除:', row);
};
</script>

3)表单容器(为后续表单验证做铺垫):

<template>
  <el-form :model="formData" label-width="120px" class="form-demo">
    <el-form-item label="用户名">
      <el-input v-model="formData.username" placeholder="请输入用户名" />
    </el-form-item>
    <el-form-item label="密码">
      <el-input v-model="formData.password" type="password" placeholder="请输入密码" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
    </el-form-item>
  </el-form>
</template>

<script setup lang="ts">
interface FormData {
  username: string;
  password: string;
}

const formData: FormData = {
  username: '',
  password: '',
};

const handleSubmit = () => {
  console.log('表单数据:', formData);
};
</script>

<style scoped>
.form-demo {
  width: 400px;
  margin: 20px;
}
</style>
1.2.4 实战踩坑:样式丢失 / 组件不生效解决方案
  1. 样式丢失:检查是否引入样式文件(全局引入需import 'element-plus/dist/index.css',按需引入若仍丢失,可手动引入组件样式);
  2. 组件不生效:确认vite.config.tsElementPlusResolver配置正确,或重启 Vite 服务;
  3. TS 类型报错:安装@types/element-pluspnpm add @types/element-plus -D)。

1.3 Ant Design Vue:安装与核心使用技巧

1.3.1 环境准备与安装

前置条件与 Element Plus 一致,安装命令:

# npm
npm install ant-design-vue --save

# pnpm
pnpm add ant-design-vue
1.3.2 全局引入 vs 按需引入

全局引入

import { createApp } from 'vue'
import App from './App.vue'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css'; // 注意:AntD Vue的样式文件名称与Element Plus不同

const app = createApp(App);
app.use(Antd);
app.mount('#app');

按需引入(生产环境首选):步骤 1:安装插件

pnpm add unplugin-vue-components unplugin-auto-import -D

步骤 2:修改vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [AntDesignVueResolver()],
    }),
    Components({
      resolvers: [AntDesignVueResolver()],
    }),
  ],
})
1.3.3 基础组件实战(卡片 / 下拉菜单 / 表单)

1)卡片组件

<template>
  <a-card title="用户信息卡片" style="width: 300px">
    <a-descriptions :column="1" bordered>
      <a-descriptions-item label="姓名">张三</a-descriptions-item>
      <a-descriptions-item label="年龄">25</a-descriptions-item>
      <a-descriptions-item label="手机号">13800138000</a-descriptions-item>
    </a-descriptions>
  </a-card>
</template>

2)下拉菜单组件

<template>
  <a-dropdown>
    <a-button type="primary">
      操作菜单 <a-icon type="down" />
    </a-button>
    <template #overlay>
      <a-menu>
        <a-menu-item key="1">
          <a-icon type="edit" /> 编辑
        </a-menu-item>
        <a-menu-item key="2">
          <a-icon type="delete" /> 删除
        </a-menu-item>
        <a-menu-item key="3">
          <a-icon type="copy" /> 复制
        </a-menu-item>
      </a-menu>
    </template>
  </a-dropdown>
</template>

3)表单容器

<template>
  <a-form
    :model="formData"
    layout="vertical"
    style="width: 400px; margin: 20px"
  >
    <a-form-item label="用户名" name="username">
      <a-input v-model:value="formData.username" placeholder="请输入用户名" />
    </a-form-item>
    <a-form-item label="密码" name="password">
      <a-input-password v-model:value="formData.password" placeholder="请输入密码" />
    </a-form-item>
    <a-form-item>
      <a-button type="primary" @click="handleSubmit">提交</a-button>
    </a-form-item>
  </a-form>
</template>

<script setup lang="ts">
interface FormData {
  username: string;
  password: string;
}

const formData: FormData = {
  username: '',
  password: '',
};

const handleSubmit = () => {
  console.log('表单数据:', formData);
};
</script>

1.4 Element Plus vs Ant Design Vue:选型决策指南

维度 Element Plus Ant Design Vue
学习成本 低(文档更贴合 Vue 开发者习惯) 中(设计理念偏阿里系,部分概念需适应)
组件丰富度 中(覆盖基础场景,特殊组件需扩展) 高(企业级组件齐全,如流程图、日历)
自定义主题 简单(提供在线主题编辑器) 中等(需配置 less 变量)
性能 优(Vue3 重写,体积小) 中(组件多,按需引入后性能可接受)
适用场景 中小型中后台、快速迭代项目 大型中台、设计规范严格的企业项目

二、Vue3 表单验证:从基础到高级(Element Plus Form & VeeValidate)

2.1 表单验证的本质:为什么不能少?

表单验证是「前端数据校验的第一道防线」,核心价值:

  1. 提升用户体验:实时提示错误,避免提交后才反馈;
  2. 降低服务端压力:过滤无效数据,减少无效请求;
  3. 保证数据合法性:防止恶意数据提交,保障业务逻辑正确。

2.2 Element Plus Form 内置验证:快速上手

Element Plus Form 组件内置了验证规则,基于async-validator实现,无需额外安装依赖,适合快速开发。

2.2.1 核心验证规则详解
规则 说明 示例
required 是否必填 { required: true }
message 错误提示文案 {message: ' 必填 '}
min/max 字符串长度 / 数字范围 { min: 6, max: 18 }
pattern 正则表达式验证 { pattern: /^1[3-9]\d{9}$/ }
validator 自定义验证函数 { validator: validatePhone }
trigger 触发验证的事件 { trigger: 'blur' }
2.2.2 自定义验证规则(同步 / 异步)

同步验证(如验证两次密码一致):

// 自定义验证函数
const validateConfirmPassword = (rule: any, value: string, callback: Function) => {
  if (value === '') {
    callback(new Error('请再次输入密码'));
  } else if (value !== formData.password) {
    callback(new Error('两次输入密码不一致!'));
  } else {
    callback();
  }
};

异步验证(如验证用户名是否已存在):

// 模拟接口请求
const checkUsernameExist = (username: string) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      // 模拟用户名已存在
      resolve(username === 'admin');
    }, 500);
  });
};

// 异步验证函数
const validateUsername = async (rule: any, value: string, callback: Function) => {
  if (value === '') {
    callback(new Error('请输入用户名'));
  } else {
    const isExist = await checkUsernameExist(value);
    if (isExist) {
      callback(new Error('用户名已存在'));
    } else {
      callback();
    }
  }
};
2.2.3 完整实战示例:用户注册表单
<template>
  <el-form
    :model="formData"
    :rules="formRules"
    ref="formRef"
    label-width="120px"
    class="register-form"
  >
    <el-form-item label="用户名" prop="username">
      <el-input v-model="formData.username" placeholder="请输入用户名" />
    </el-form-item>
    <el-form-item label="手机号" prop="phone">
      <el-input v-model="formData.phone" placeholder="请输入手机号" />
    </el-form-item>
    <el-form-item label="密码" prop="password">
      <el-input v-model="formData.password" type="password" placeholder="请输入密码" />
    </el-form-item>
    <el-form-item label="确认密码" prop="confirmPassword">
      <el-input v-model="formData.confirmPassword" type="password" placeholder="请再次输入密码" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="handleSubmit">注册</el-button>
      <el-button @click="handleReset">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';

// 表单数据
interface FormData {
  username: string;
  phone: string;
  password: string;
  confirmPassword: string;
}

const formData = ref<FormData>({
  username: '',
  phone: '',
  password: '',
  confirmPassword: '',
});

// 表单Ref
const formRef = ref<FormInstance>();

// 模拟用户名校验接口
const checkUsernameExist = (username: string) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(username === 'admin');
    }, 500);
  });
};

// 自定义验证规则
const validateUsername = async (rule: any, value: string, callback: Function) => {
  if (!value) {
    callback(new Error('请输入用户名'));
  } else {
    const isExist = await checkUsernameExist(value);
    isExist ? callback(new Error('用户名已存在')) : callback();
  }
};

const validateConfirmPassword = (rule: any, value: string, callback: Function) => {
  if (!value) {
    callback(new Error('请再次输入密码'));
  } else if (value !== formData.value.password) {
    callback(new Error('两次输入密码不一致'));
  } else {
    callback();
  }
};

// 表单验证规则
const formRules = ref<FormRules>({
  username: [
    { validator: validateUsername, trigger: 'blur' },
  ],
  phone: [
    { required: true, message: '请输入手机号', trigger: 'blur' },
    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' },
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    { min: 6, max: 18, message: '密码长度需在6-18位之间', trigger: 'blur' },
  ],
  confirmPassword: [
    { validator: validateConfirmPassword, trigger: 'blur' },
  ],
});

// 提交表单
const handleSubmit = async () => {
  if (!formRef.value) return;
  try {
    // 触发表单验证
    await formRef.value.validate();
    // 验证通过,提交数据
    console.log('表单验证通过,提交数据:', formData.value);
    // 这里可调用接口提交数据
  } catch (error) {
    console.log('表单验证失败:', error);
  }
};

// 重置表单
const handleReset = () => {
  if (!formRef.value) return;
  formRef.value.resetFields();
};
</script>

<style scoped>
.register-form {
  width: 400px;
  margin: 20px;
}
</style>

2.3 VeeValidate:更灵活的表单验证方案

        VeeValidate 是 Vue3 生态中专门的表单验证库,相比 Element Plus 内置验证,它更灵活、可复用性更高,支持复杂场景(如动态表单、多语言、跨字段验证)。

2.3.1 VeeValidate 核心设计理念

VeeValidate 采用「组件化」设计,核心组件:

  • Form:表单容器,负责管理整个表单的验证状态;
  • Field:表单字段,绑定验证规则,替代原生 input / 组件;
  • ErrorMessage:错误提示组件,自动显示字段验证错误;
  • useForm:组合式 API,用于手动控制表单验证。
2.3.2 安装与全局配置

安装命令:

# 核心库
pnpm add vee-validate@4

# 内置验证规则(可选,推荐安装)
pnpm add @vee-validate/rules

# 多语言支持(可选)
pnpm add @vee-validate/i18n

全局配置(在main.ts中):

import { createApp } from 'vue'
import App from './App.vue'
// 引入VeeValidate核心组件
import { Form, Field, ErrorMessage, defineRule } from 'vee-validate';
// 引入内置验证规则
import { required, min, max, regex, confirmed } from '@vee-validate/rules';

// 注册内置验证规则
defineRule('required', required);
defineRule('min', min);
defineRule('max', max);
defineRule('regex', regex);
defineRule('confirmed', confirmed);

const app = createApp(App);
// 全局注册组件
app.component('Form', Form);
app.component('Field', Field);
app.component('ErrorMessage', ErrorMessage);

app.mount('#app');
2.3.3 内置规则快速使用

直接在Field组件中通过rules属性绑定规则:

<template>
  <Form @submit="handleSubmit">
    <div class="form-item">
      <label>用户名:</label>
      <Field
        name="username"
        v-model="formData.username"
        rules="required|min:3|max:10"
        as="el-input"
        placeholder="请输入用户名"
      />
      <ErrorMessage name="username" class="error" />
    </div>

    <div class="form-item">
      <label>密码:</label>
      <Field
        name="password"
        v-model="formData.password"
        rules="required|min:6|max:18"
        as="el-input"
        type="password"
        placeholder="请输入密码"
      />
      <ErrorMessage name="password" class="error" />
    </div>

    <button type="submit">提交</button>
  </Form>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const formData = ref({
  username: '',
  password: '',
});

const handleSubmit = (values: any) => {
  console.log('表单数据:', values);
};
</script>

<style scoped>
.form-item {
  margin: 10px 0;
  display: flex;
  flex-direction: column;
  width: 300px;
}
.error {
  color: #f56c6c;
  font-size: 12px;
  margin-top: 5px;
}
</style>
2.3.4 自定义验证规则(实战场景)

1)同步自定义规则(验证手机号格式):

import { defineRule } from 'vee-validate';

// 自定义手机号验证规则
defineRule('phone', (value: string) => {
  if (!value) {
    return '请输入手机号';
  }
  const reg = /^1[3-9]\d{9}$/;
  if (!reg.test(value)) {
    return '请输入正确的手机号格式';
  }
  return true;
});

2)异步自定义规则(验证用户名是否存在):

// 模拟接口请求
const checkUsername = (username: string) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(username !== 'admin');
    }, 500);
  });
};

// 自定义异步验证规则
defineRule('usernameUnique', async (value: string) => {
  if (!value) {
    return '请输入用户名';
  }
  const isUnique = await checkUsername(value);
  if (!isUnique) {
    return '用户名已存在';
  }
  return true;
});
2.3.5 多语言适配:让验证提示更友好

步骤 1:配置多语言

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { Form, Field, ErrorMessage, defineRule } from 'vee-validate';
import { required, min, max } from '@vee-validate/rules';
// 引入多语言相关
import { localize, setLocale } from '@vee-validate/i18n';
import zhCN from '@vee-validate/i18n/dist/locale/zh_CN.json';

// 注册规则
defineRule('required', required);
defineRule('min', min);
defineRule('max', max);

// 配置中文
localize({
  zh_CN: zhCN,
});
setLocale('zh_CN');

// 注册组件
app.component('Form', Form);
app.component('Field', Field);
app.component('ErrorMessage', ErrorMessage);

app.mount('#app');

步骤 2:使用多语言规则(无需手动写提示文案):

<Field
  name="password"
  v-model="formData.password"
  rules="required|min:6|max:18"
  as="el-input"
  type="password"
  placeholder="请输入密码"
/>
<ErrorMessage name="password" class="error" />

此时错误提示会自动显示中文:「此字段为必填项」「此字段至少包含 6 个字符」等。

2.3.6 完整实战示例:复杂订单表单验证
<template>
  <Form @submit="handleSubmit" class="order-form">
    <!-- 收货地址 -->
    <div class="form-group">
      <h4>收货信息</h4>
      <div class="form-item">
        <label>收货人:</label>
        <Field
          name="receiver"
          v-model="formData.receiver"
          rules="required|min:2|max:10"
          as="el-input"
          placeholder="请输入收货人姓名"
        />
        <ErrorMessage name="receiver" class="error" />
      </div>

      <div class="form-item">
        <label>手机号:</label>
        <Field
          name="phone"
          v-model="formData.phone"
          rules="required|phone"
          as="el-input"
          placeholder="请输入手机号"
        />
        <ErrorMessage name="phone" class="error" />
      </div>

      <div class="form-item">
        <label>地址:</label>
        <Field
          name="address"
          v-model="formData.address"
          rules="required|min:10"
          as="el-input"
          type="textarea"
          placeholder="请输入详细地址"
        />
        <ErrorMessage name="address" class="error" />
      </div>
    </div>

    <!-- 支付方式 -->
    <div class="form-group">
      <h4>支付方式</h4>
      <div class="form-item">
        <Field
          name="payType"
          v-model="formData.payType"
          rules="required"
          as="el-radio-group"
        >
          <el-radio label="wechat">微信支付</el-radio>
          <el-radio label="alipay">支付宝</el-radio>
        </Field>
        <ErrorMessage name="payType" class="error" />
      </div>
    </div>

    <!-- 备注 -->
    <div class="form-item">
      <label>备注:</label>
      <Field
        name="remark"
        v-model="formData.remark"
        rules="max:100"
        as="el-input"
        type="textarea"
        placeholder="请输入备注(最多100字)"
      />
      <ErrorMessage name="remark" class="error" />
    </div>

    <el-button type="primary" type="submit">提交订单</el-button>
  </Form>
</template>

<script setup lang="ts">
import { ref, defineProps } from 'vue';
import { defineRule } from 'vee-validate';

// 自定义手机号规则
defineRule('phone', (value: string) => {
  if (!value) return '请输入手机号';
  const reg = /^1[3-9]\d{9}$/;
  if (!reg.test(value)) return '请输入正确的手机号格式';
  return true;
});

// 表单数据
interface FormData {
  receiver: string;
  phone: string;
  address: string;
  payType: string;
  remark: string;
}

const formData = ref<FormData>({
  receiver: '',
  phone: '',
  address: '',
  payType: '',
  remark: '',
});

// 提交表单
const handleSubmit = (values: FormData) => {
  console.log('订单提交成功:', values);
  // 调用接口提交订单
};
</script>

<style scoped>
.order-form {
  width: 500px;
  margin: 20px;
}
.form-group {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
}
.form-item {
  margin: 10px 0;
  display: flex;
  flex-direction: column;
}
.error {
  color: #f56c6c;
  font-size: 12px;
  margin-top: 5px;
}
</style>

2.4 两种验证方案对比:什么时候用哪个?

维度 Element Plus Form 内置验证 VeeValidate
依赖 无(内置) 需额外安装
学习成本 低(贴合 Element 组件使用) 中(需学习专属 API)
灵活性 中(适合简单表单) 高(支持动态表单、跨字段验证)
可复用性 低(规则与组件强绑定) 高(规则可全局注册、复用)
多语言 需手动配置 内置多语言支持
适用场景 简单表单、快速开发 复杂表单、动态表单、企业级项目

三、综合实战:UI 组件库 + 表单验证全流程

3.1 需求:搭建带严格验证的用户信息采集表单

  • 技术选型:Element Plus(UI) + VeeValidate(验证)
  • 核心需求:用户名唯一验证、手机号格式验证、密码强度验证、跨字段验证(两次密码一致)

3.2 完整代码实现与解析

<template>
  <div class="container">
    <h2>用户信息采集表单</h2>
    <Form @submit="onSubmit" class="form">
      <!-- 用户名 -->
      <el-form-item label="用户名">
        <Field
          name="username"
          v-model="formData.username"
          rules="required|min:3|max:10|usernameUnique"
          as="el-input"
          placeholder="请输入3-10位用户名"
        />
        <ErrorMessage name="username" class="error" />
      </el-form-item>

      <!-- 手机号 -->
      <el-form-item label="手机号">
        <Field
          name="phone"
          v-model="formData.phone"
          rules="required|phone"
          as="el-input"
          placeholder="请输入手机号"
        />
        <ErrorMessage name="phone" class="error" />
      </el-form-item>

      <!-- 密码 -->
      <el-form-item label="密码">
        <Field
          name="password"
          v-model="formData.password"
          rules="required|passwordStrength"
          as="el-input"
          type="password"
          placeholder="请输入密码(含字母+数字,6-18位)"
        />
        <ErrorMessage name="password" class="error" />
      </el-form-item>

      <!-- 确认密码 -->
      <el-form-item label="确认密码">
        <Field
          name="confirmPassword"
          v-model="formData.confirmPassword"
          rules="required|confirmed:password"
          as="el-input"
          type="password"
          placeholder="请再次输入密码"
        />
        <ErrorMessage name="confirmPassword" class="error" />
      </el-form-item>

      <el-form-item>
        <el-button type="primary" type="submit">提交</el-button>
        <el-button @click="onReset">重置</el-button>
      </el-form-item>
    </Form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { defineRule, useForm } from 'vee-validate';

// 1. 定义自定义验证规则
// 1.1 用户名唯一性验证(异步)
const checkUsernameUnique = async (username: string) => {
  // 模拟接口请求
  return new Promise((resolve) => {
    setTimeout(() => {
      // 模拟admin、test用户名已存在
      const existUsernames = ['admin', 'test'];
      resolve(!existUsernames.includes(username));
    }, 500);
  });
};
defineRule('usernameUnique', async (value) => {
  if (!value) return '请输入用户名';
  const isUnique = await checkUsernameUnique(value);
  return isUnique ? true : '用户名已存在';
});

// 1.2 手机号验证
defineRule('phone', (value) => {
  if (!value) return '请输入手机号';
  const reg = /^1[3-9]\d{9}$/;
  return reg.test(value) ? true : '请输入正确的手机号格式';
});

// 1.3 密码强度验证
defineRule('passwordStrength', (value) => {
  if (!value) return '请输入密码';
  if (value.length < 6 || value.length > 18) return '密码长度需在6-18位之间';
  const reg = /^(?=.*[a-zA-Z])(?=.*\d).+$/;
  return reg.test(value) ? true : '密码需包含字母和数字';
});

// 2. 表单数据
interface FormData {
  username: string;
  phone: string;
  password: string;
  confirmPassword: string;
}
const formData = ref<FormData>({
  username: '',
  phone: '',
  password: '',
  confirmPassword: '',
});

// 3. 表单方法
const { resetForm } = useForm();
// 提交表单
const onSubmit = (values: FormData) => {
  console.log('表单提交成功:', values);
  // 实际项目中调用接口提交数据
};
// 重置表单
const onReset = () => {
  resetForm();
  formData.value = {
    username: '',
    phone: '',
    password: '',
    confirmPassword: '',
  };
};
</script>

<style scoped>
.container {
  width: 600px;
  margin: 50px auto;
}
.form {
  margin-top: 20px;
}
.error {
  color: #f56c6c;
  font-size: 12px;
  margin-top: 5px;
  display: block;
}
</style>

四、总结与进阶建议

4.1 核心总结

  1. UI 组件库选型:Element Plus 适合快速开发、中小项目;Ant Design Vue 适合大型企业级项目,需平衡学习成本与组件丰富度;
  2. 表单验证选型:简单表单用 Element Plus 内置验证,复杂表单 / 多语言场景用 VeeValidate;
  3. 性能优化:UI 组件库务必按需引入,减少打包体积;表单验证规则按需注册,避免全局冗余。

4.2 进阶建议

  1. 自定义 UI 组件库主题:基于 Element Plus/Ant Design Vue 的主题配置,适配项目品牌风格;
  2. 封装通用验证规则:将项目中常用的验证规则(如手机号、身份证、邮箱)封装成独立文件,全局引入;
  3. 结合 TypeScript:为表单数据、验证规则添加完整类型定义,提升代码可维护性;
  4. 表单状态管理:复杂表单可结合 Pinia 管理表单数据,实现跨组件数据共享。

最后

        本文从实战角度讲解了 Vue3 生态中最核心的 UI 组件库和表单验证工具,覆盖安装、使用、优化、选型全流程。如果对你有帮助,欢迎点赞 + 收藏 + 关注,后续会持续更新 Vue3 生态实战内容(如状态管理、路由、打包优化)。

如果有任何问题或不同见解,欢迎在评论区交流哈~

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐