Skip to content

Vben 组件使用指南

本文档详细介绍 Vue Vben Admin 框架中的核心组件使用方法。

📚 目录


VbenForm 表单组件

VbenForm 是一个基于 Schema 配置的动态表单组件,支持多种表单控件和验证规则。

基础用法

vue
<script setup lang="ts">
import { useVbenForm } from '#/adapter/form';
import { message } from 'ant-design-vue';

const [Form, formApi] = useVbenForm({
  schema: [
    {
      fieldName: 'username',
      label: '用户名',
      component: 'Input',
      componentProps: {
        placeholder: '请输入用户名'
      },
      rules: 'required'
    },
    {
      fieldName: 'email',
      label: '邮箱',
      component: 'Input',
      rules: 'required|email'
    }
  ],
  handleSubmit: async (values) => {
    console.log('表单值:', values);
    message.success('提交成功');
  }
});
</script>

<template>
  <Form />
</template>

表单布局

vue
<script setup lang="ts">
const [Form] = useVbenForm({
  layout: 'horizontal',  // horizontal | vertical | inline
  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
  commonConfig: {
    colon: true,
    componentProps: {
      class: 'w-full'
    }
  },
  schema: [
    { fieldName: 'name', label: '姓名', component: 'Input' }
  ]
});
</script>

常用组件类型

输入框

vue
<script setup lang="ts">
const [Form] = useVbenForm({
  schema: [
    // 普通输入框
    {
      fieldName: 'username',
      label: '用户名',
      component: 'Input',
      componentProps: {
        placeholder: '请输入用户名',
        maxlength: 20,
        showCount: true
      }
    },
    // 密码输入框
    {
      fieldName: 'password',
      label: '密码',
      component: 'InputPassword'
    },
    // 数字输入框
    {
      fieldName: 'age',
      label: '年龄',
      component: 'InputNumber',
      componentProps: {
        min: 0,
        max: 150
      }
    },
    // 文本域
    {
      fieldName: 'description',
      label: '描述',
      component: 'Textarea',
      componentProps: {
        rows: 4,
        maxlength: 200,
        showCount: true
      }
    }
  ]
});
</script>

选择器

vue
<script setup lang="ts">
const [Form] = useVbenForm({
  schema: [
    // 下拉选择
    {
      fieldName: 'gender',
      label: '性别',
      component: 'Select',
      componentProps: {
        options: [
          { label: '男', value: 'male' },
          { label: '女', value: 'female' }
        ]
      }
    },
    // 多选
    {
      fieldName: 'hobbies',
      label: '爱好',
      component: 'Select',
      componentProps: {
        mode: 'multiple',
        options: [
          { label: '读书', value: 'reading' },
          { label: '运动', value: 'sports' }
        ]
      }
    },
    // 树形选择
    {
      fieldName: 'dept',
      label: '部门',
      component: 'TreeSelect',
      componentProps: {
        treeData: [
          {
            label: '技术部',
            value: 'tech',
            children: [
              { label: '前端组', value: 'frontend' },
              { label: '后端组', value: 'backend' }
            ]
          }
        ]
      }
    }
  ]
});
</script>

API 选择器

vue
<script setup lang="ts">
import { getUserListApi } from '#/api/user';

const [Form] = useVbenForm({
  schema: [
    {
      fieldName: 'userId',
      label: '用户',
      component: 'ApiSelect',
      componentProps: {
        api: getUserListApi,
        afterFetch: (data) => {
          return data.map(item => ({
            label: item.realName,
            value: item.id
          }));
        }
      }
    }
  ]
});
</script>

日期时间

vue
<script setup lang="ts">
const [Form] = useVbenForm({
  schema: [
    {
      fieldName: 'birthday',
      label: '生日',
      component: 'DatePicker',
      componentProps: {
        format: 'YYYY-MM-DD'
      }
    },
    {
      fieldName: 'dateRange',
      label: '日期范围',
      component: 'RangePicker',
      componentProps: {
        format: 'YYYY-MM-DD',
        placeholder: ['开始日期', '结束日期']
      }
    }
  ],
  fieldMappingTime: [
    ['dateRange', ['startDate', 'endDate'], 'YYYY-MM-DD']
  ]
});
</script>

单选和多选

vue
<script setup lang="ts">
const [Form] = useVbenForm({
  schema: [
    {
      fieldName: 'status',
      label: '状态',
      component: 'RadioGroup',
      componentProps: {
        options: [
          { label: '启用', value: 1 },
          { label: '禁用', value: 0 }
        ]
      }
    },
    {
      fieldName: 'permissions',
      label: '权限',
      component: 'CheckboxGroup',
      componentProps: {
        options: [
          { label: '查看', value: 'view' },
          { label: '编辑', value: 'edit' },
          { label: '删除', value: 'delete' }
        ]
      }
    },
    {
      fieldName: 'enabled',
      label: '启用',
      component: 'Switch'
    }
  ]
});
</script>

表单验证

内置规则

vue
<script setup lang="ts">
const [Form] = useVbenForm({
  schema: [
    {
      fieldName: 'username',
      label: '用户名',
      component: 'Input',
      rules: 'required'
    },
    {
      fieldName: 'email',
      label: '邮箱',
      component: 'Input',
      rules: 'required|email'
    },
    {
      fieldName: 'phone',
      label: '手机号',
      component: 'Input',
      rules: 'required|phone'
    }
  ]
});
</script>

Zod 验证

vue
<script setup lang="ts">
import { useVbenForm, z } from '#/adapter/form';

const [Form] = useVbenForm({
  schema: [
    {
      fieldName: 'email',
      label: '邮箱',
      component: 'Input',
      rules: z.string().email('请输入有效的邮箱地址')
    },
    {
      fieldName: 'age',
      label: '年龄',
      component: 'InputNumber',
      rules: z.number()
        .min(18, '年龄必须大于18岁')
        .max(60, '年龄必须小于60岁')
    },
    {
      fieldName: 'password',
      label: '密码',
      component: 'InputPassword',
      rules: z.string()
        .min(6, '密码至少6位')
        .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, '密码必须包含大小写字母和数字')
    }
  ]
});
</script>

表单 API

vue
<script setup lang="ts">
const [Form, formApi] = useVbenForm({
  schema: [
    { fieldName: 'username', label: '用户名', component: 'Input' }
  ]
});

// 获取表单值
function getValues() {
  const values = formApi.getValues();
  console.log('表单值:', values);
}

// 设置表单值
function setValues() {
  formApi.setValues({
    username: '张三'
  });
}

// 重置表单
function resetForm() {
  formApi.resetForm();
}

// 验证表单
async function validateForm() {
  const { valid, values } = await formApi.validate();
  if (valid) {
    console.log('验证通过:', values);
  }
}

// 动态控制字段
function toggleField() {
  formApi.updateSchema({
    fieldName: 'username',
    visible: false  // 隐藏字段
  });
}
</script>

VxeGrid 表格组件

VxeGrid 是一个功能强大的表格组件,支持分页、排序、筛选等功能。

基础表格

vue
<script setup lang="ts">
import { useVxeGrid } from '#/adapter/vxe-table';

const [Grid] = useVxeGrid({
  columns: [
    { field: 'id', title: 'ID', width: 80 },
    { field: 'username', title: '用户名', width: 150 },
    { field: 'email', title: '邮箱', minWidth: 200 }
  ],
  data: [
    { id: 1, username: 'admin', email: 'admin@example.com' }
  ]
});
</script>

<template>
  <Grid />
</template>

分页表格

vue
<script setup lang="ts">
import { useVxeGrid } from '#/adapter/vxe-table';
import { getUserListApi } from '#/api/user';

const [Grid, gridApi] = useVxeGrid({
  columns: [
    { type: 'checkbox', width: 50 },
    { type: 'seq', title: '序号', width: 80 },
    { field: 'username', title: '用户名' },
    { field: 'email', title: '邮箱' }
  ],
  pagerConfig: {
    enabled: true,
    currentPage: 1,
    pageSize: 10,
    pageSizes: [10, 20, 50, 100]
  },
  proxyConfig: {
    ajax: {
      query: async ({ page }) => {
        const result = await getUserListApi({
          page: page.currentPage,
          pageSize: page.pageSize
        });
        return {
          result: result.list,
          page: { total: result.total }
        };
      }
    }
  }
});

// 刷新表格
function refresh() {
  gridApi.query();
}

// 获取选中行
function getSelectedRows() {
  const rows = gridApi.getCheckboxRecords();
  console.log('选中行:', rows);
}
</script>

操作列

vue
<script setup lang="ts">
import { h } from 'vue';
import { Button, Popconfirm } from 'ant-design-vue';

const [Grid] = useVxeGrid({
  columns: [
    { field: 'username', title: '用户名' },
    {
      title: '操作',
      width: 200,
      fixed: 'right',
      slots: {
        default: ({ row }) => [
          h(Button, {
            type: 'link',
            size: 'small',
            onClick: () => handleEdit(row)
          }, () => '编辑'),
          h(Popconfirm, {
            title: '确定要删除吗?',
            onConfirm: () => handleDelete(row)
          }, {
            default: () => h(Button, {
              type: 'link',
              danger: true,
              size: 'small'
            }, () => '删除')
          })
        ]
      }
    }
  ]
});

function handleEdit(row) {
  console.log('编辑:', row);
}

function handleDelete(row) {
  console.log('删除:', row);
}
</script>

VbenModal 模态框组件

基础用法

vue
<script setup lang="ts">
import { useVbenModal } from '@vben/common-ui';

const [Modal, modalApi] = useVbenModal({
  title: '提示',
  onConfirm: () => {
    console.log('确认');
    modalApi.close();
  }
});

function openModal() {
  modalApi.open();
}
</script>

<template>
  <button @click="openModal">打开模态框</button>
  <Modal>
    <p>这是模态框内容</p>
  </Modal>
</template>

表单模态框

vue
<script setup lang="ts">
import { useVbenModal } from '@vben/common-ui';
import { useVbenForm } from '#/adapter/form';

const [Form, formApi] = useVbenForm({
  schema: [
    {
      fieldName: 'username',
      label: '用户名',
      component: 'Input',
      rules: 'required'
    }
  ],
  showDefaultActions: false
});

const [Modal, modalApi] = useVbenModal({
  title: '添加用户',
  async onConfirm() {
    const { valid, values } = await formApi.validate();
    if (valid) {
      console.log('提交:', values);
      modalApi.close();
    }
  }
});
</script>

<template>
  <button @click="modalApi.open()">添加用户</button>
  <Modal>
    <Form />
  </Modal>
</template>

VbenDrawer 抽屉组件

vue
<script setup lang="ts">
import { useVbenDrawer } from '@vben/common-ui';

const [Drawer, drawerApi] = useVbenDrawer({
  title: '详情',
  placement: 'right',
  width: '500px',
  onConfirm: () => {
    drawerApi.close();
  }
});
</script>

<template>
  <button @click="drawerApi.open()">打开抽屉</button>
  <Drawer>
    <p>这是抽屉内容</p>
  </Drawer>
</template>

图标组件

使用 Iconify

vue
<script setup lang="ts">
import { createIconifyIcon } from '@vben/icons';

const UserIcon = createIconifyIcon('lucide:user');
const SettingsIcon = createIconifyIcon('lucide:settings');
const HomeIcon = createIconifyIcon('lucide:home');
</script>

<template>
  <div class="flex gap-4">
    <UserIcon class="size-6" />
    <SettingsIcon class="size-6" />
    <HomeIcon class="size-6" />
  </div>
</template>

常用图标

lucide:user          用户
lucide:settings      设置
lucide:home          首页
lucide:search        搜索
lucide:plus          加号
lucide:edit          编辑
lucide:trash         删除
lucide:eye           查看
lucide:download      下载
lucide:upload        上传

更多图标:https://icon-sets.iconify.design/


完整示例

用户管理页面完整示例:

vue
<script setup lang="ts">
import { h, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeGrid } from '#/adapter/vxe-table';
import { useVbenForm } from '#/adapter/form';
import { Button, Popconfirm, message } from 'ant-design-vue';
import { createIconifyIcon } from '@vben/icons';
import { getUserListApi, createUserApi, updateUserApi, deleteUserApi } from '#/api/user';

const PlusIcon = createIconifyIcon('lucide:plus');

// 表格
const [Grid, gridApi] = useVxeGrid({
  columns: [
    { type: 'seq', title: '序号', width: 80 },
    { field: 'username', title: '用户名' },
    { field: 'realName', title: '真实姓名' },
    { field: 'email', title: '邮箱' },
    {
      title: '操作',
      width: 150,
      fixed: 'right',
      slots: {
        default: ({ row }) => [
          h(Button, {
            type: 'link',
            size: 'small',
            onClick: () => handleEdit(row)
          }, () => '编辑'),
          h(Popconfirm, {
            title: '确定要删除吗?',
            onConfirm: () => handleDelete(row)
          }, {
            default: () => h(Button, {
              type: 'link',
              danger: true,
              size: 'small'
            }, () => '删除')
          })
        ]
      }
    }
  ],
  pagerConfig: { enabled: true },
  proxyConfig: {
    ajax: {
      query: async ({ page }) => {
        const result = await getUserListApi({
          page: page.currentPage,
          pageSize: page.pageSize
        });
        return {
          result: result.list,
          page: { total: result.total }
        };
      }
    }
  }
});

// 表单
const [Form, formApi] = useVbenForm({
  schema: [
    {
      fieldName: 'username',
      label: '用户名',
      component: 'Input',
      rules: 'required'
    },
    {
      fieldName: 'realName',
      label: '真实姓名',
      component: 'Input',
      rules: 'required'
    },
    {
      fieldName: 'email',
      label: '邮箱',
      component: 'Input',
      rules: 'required|email'
    }
  ],
  showDefaultActions: false
});

// 模态框
const formMode = ref<'add' | 'edit'>('add');
const [Modal, modalApi] = useVbenModal({
  title: () => formMode.value === 'add' ? '添加用户' : '编辑用户',
  async onConfirm() {
    const { valid, values } = await formApi.validate();
    if (valid) {
      if (formMode.value === 'add') {
        await createUserApi(values);
        message.success('添加成功');
      } else {
        await updateUserApi(values.id, values);
        message.success('更新成功');
      }
      modalApi.close();
      gridApi.query();
    }
  }
});

function handleAdd() {
  formMode.value = 'add';
  formApi.resetForm();
  modalApi.open();
}

function handleEdit(row: any) {
  formMode.value = 'edit';
  formApi.setValues(row);
  modalApi.open();
}

async function handleDelete(row: any) {
  await deleteUserApi(row.id);
  message.success('删除成功');
  gridApi.query();
}
</script>

<template>
  <Page title="用户管理">
    <template #extra>
      <Button type="primary" @click="handleAdd">
        <PlusIcon class="mr-1" />
        新增
      </Button>
    </template>
    
    <Grid />
    
    <Modal>
      <Form />
    </Modal>
  </Page>
</template>

参考资源


祝你开发顺利! 🚀

MIT License