npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vue-ui-kit/ant

v2.3.8

Published

Vue3 UI Kit based on Ant Design

Readme

基于 Ant Design Vue 的 Vue 3 UI 组件库,提供增强的表单、网格和实用组件。

安装

npm install @vue-ui-kit/ant
# 或
yarn add @vue-ui-kit/ant
# 或
pnpm add @vue-ui-kit/ant
/*main.ts*/
import { createApp } from 'vue';
import App from './App.vue';
import Antd from 'ant-design-vue';
import UIKit from '@vue-ui-kit/ant';
import '@vue-ui-kit/ant/scss';
/*创建渲染器(推荐使用tsx配置)*/
import { setupKit } from './setup/kit.tsx';

/*创建格式化*/
UIKit.addFormatter({
  test: ({ row, column, cellValue }) => 'test:...' + 'field:' + column.field + '...v:' + cellvalue,
});
createApp(App).use(Antd).use(UIKit).mount('#app');
/*kit.tsx*/
import UIKit from '@vue-ui-kit/ant';
import { TypographyParagraph, Switch } from 'ant-design-vue';

export const setupKit = () => {
  /*注册$paragraph作为单元格渲染器*/
  UIKit.addRender('$paragraph', {
    renderDefault({ props = {} }: RenderOptions, { row, field }: RenderTableParams) {
      const content = props.getContent?.({ row, field }) ?? (valued(field) ? row[field!] : '');
      return valued(field) ? (
        <TypographyParagraph
          {...merge({}, defaultProps.$paragraph, omit(props, ['content', 'getContent']))}
          content={content}
        />
      ) : null;
    },
  });
  /*注册$switch 作为表单渲染器*/
  UIKit.addRender('$switch', {
    renderItemContent(
      { props = {}, events = {} }: RenderOptions,
      { data, field }: RenderFormParams,
    ) {
      return valued(field) ? (
        <Switch
          v-model:checked={data[field!]}
          {...props}
          onChange={(...arg) => {
            events.change?.({ data, field }, ...arg);
          }}
        />
      ) : null;
    },
  });
};

/*
* 已内置了渲染器
* 
  $input: Input,
  AInput: Input,
  $textarea: Textarea,
  Textarea: Textarea,
  $number: InputNumber,
  AInputNumber: InputNumber,
  $select: Select,
  ASelect: Select,
  $date: DatePicker,
  ADatePicker: DatePicker,
  $range: RangePicker,
  ARangePicker: RangePicker,
  AAutoComplete: AutoComplete,
  $Cascader: Cascader,
  ACascader: Cascader,
  ACheckbox: Checkbox,
  AMentions: Mentions,
  ARate: Rate,
  ASlider: Slider,
  $time: TimePicker,
  ATimePicker: TimePicker,
  ATreeSelect: TreeSelect,

* 
* */

环境要求

  • Node.js >= 16
  • Vue >= 3.2.0
  • ant-design-vue >= 4.0.0
  • @ant-design/icons-vue >= 7.0.0

组件

PGrid

增强的数据表格组件,集成了查询表单、分页和工具栏功能。

基础示例

<script setup lang="ts">
import { computed } from 'vue';
import { PGridProps, labelColDict } from '@vue-ui-kit/ant';

const gridSetting = computed<PGridProps<Student, { keyword?: string }>>(() => ({
  columns: [
    { field: 'name', title: '姓名', width: 200 },
    { field: 'email', title: '邮箱', width: 200 },
    { field: 'age', title: '年龄', width: 100 },
  ],
  formConfig: {
    items: [
      {
        field: 'keyword',
        title: '关键字',
        labelCol: labelColDict[3],
        itemRender: {
          name: '$input',
          props: { placeholder: '请输入关键字...' },
        },
      },
    ],
  },
  proxyConfig: {
    ajax: {
      query: ({ form, page }) => api.getStudents({ ...form, ...page }),
    },
  },
}));
</script>

<template>
  <p-grid v-bind="gridSetting" />
</template>

PForm

增强的表单组件,具有简化的配置和动态字段功能。

属性

| 属性 | 类型 | 说明 | 默认值 | | --- | --- | --- | --- | | items | PFormItemProps[] | 表单项配置数组 | - | | data | T | 表单数据对象 | - | | customReset | () => void | 自定义重置函数 | - | | labelCol | ColProps | 标签列布局 | { span: 6 } | | wrapperCol | ColProps | 包装列布局 | { span: 16 } | | ...其他 | FormProps | 所有 ant-design-vue Form 的属性 | - |

事件

| 事件 | 说明 | 参数 | | --- | --- | --- | | apply | 表单提交时触发 | (formData: T) => void | | reset | 表单重置时触发 | () => void |

PFormItemProps

| 属性 | 类型 | 说明 | 默认值 | | --- | --- | --- | --- | | field | string | 表单字段名 | - | | title | string | 字段标签 | - | | span | number | 栅格跨度 (1-24) | - | | colon | boolean | 标签后显示冒号 | true | | labelCol | ColProps | 标签列布局 | - | | wrapperCol | ColProps | 包装列布局 | - | | forceRequired | boolean | 显示必填标记(仅视觉效果) | false | | align | 'left' \| 'right' \| 'center' | 文本对齐方式 | 'left' | | col | ColProps | 栅格列属性 | - | | rule | Rule[] | 验证规则 | - | | itemRender | ItemRender | 字段渲染器配置 | - | | tooltipConfig | TooltipConfig | 提示配置 | - | | slots | object | 自定义插槽渲染器 | - |

内置渲染器

  • $input: 输入框
  • $textarea: 文本域
  • $number: 数字输入框
  • $select: 下拉选择
  • $date: 日期选择器
  • $range: 日期范围选择器
  • $time: 时间选择器
  • ASwitch: 开关组件
  • ACheckbox: 复选框
  • ARate: 评分组件
  • ASlider: 滑动输入条

基础示例

<script setup lang="ts">
import { ref, computed } from 'vue';
import { PFormProps } from '@vue-ui-kit/ant';

interface UserForm {
  name: string;
  email: string;
  age?: number;
  gender: string;
  skills: string[];
}

const formData = ref<UserForm>({
  name: '',
  email: '',
  age: undefined,
  gender: '',
  skills: [],
});

const formSetting = computed<PFormProps<UserForm>>(() => ({
  items: [
    {
      field: 'name',
      title: '姓名',
      span: 12,
      rule: [{ required: true, message: '请输入姓名' }],
      itemRender: {
        name: '$input',
        props: { placeholder: '请输入姓名' },
      },
    },
    {
      field: 'email',
      title: '邮箱',
      span: 12,
      rule: [
        { required: true, message: '请输入邮箱' },
        { type: 'email', message: '邮箱格式不正确' },
      ],
      itemRender: {
        name: '$input',
        props: { placeholder: '请输入邮箱' },
      },
    },
    {
      field: 'gender',
      title: '性别',
      span: 12,
      rule: [{ required: true, message: '请选择性别' }],
      itemRender: {
        name: '$select',
        props: {
          placeholder: '请选择性别',
          options: [
            { label: '男', value: 'male' },
            { label: '女', value: 'female' },
          ],
        },
      },
    },
    {
      field: 'skills',
      title: '技能',
      span: 24,
      itemRender: {
        name: '$select',
        props: {
          mode: 'multiple',
          placeholder: '请选择技能',
          options: [
            { label: 'Vue.js', value: 'vue' },
            { label: 'React', value: 'react' },
            { label: 'Angular', value: 'angular' },
          ],
        },
      },
    },
  ],
}));

const handleSubmit = (data: UserForm) => {
  console.log('表单提交:', data);
};
</script>

<template>
  <p-form 
    v-bind="formSetting" 
    :data="formData"
    @apply="handleSubmit"
  />
</template>

自定义插槽示例

<script setup lang="tsx">
import { ref, computed } from 'vue';

const formData = ref({
  name: '',
  isActive: false,
});

const formSetting = computed(() => ({
  items: [
    {
      field: 'isActive',
      title: '状态',
      span: 24,
      slots: {
        default: ({ data }) => (
          <a-switch
            v-model:checked={data.isActive}
            checkedChildren="启用"
            unCheckedChildren="禁用"
          />
        ),
      },
    },
  ],
}));
</script>

PFormGroup

动态表单组组件,用于管理多个表单实例,支持添加/删除功能。

属性

| 属性 | 类型 | 说明 | 默认值 | | --- | --- | --- | --- | | v-model | Array<T & { __index: number }> | 表单组数据数组 | [] | | getFormSetting | (data: T) => PFormProps<T> | 获取表单配置的函数 | - | | title | string | 组标题 | - | | tabLabel | string | 自定义标签页标签模板 | - | | editAble | boolean | 标签页是否可编辑 | true | | showAdd | boolean | 显示添加按钮 | true | | lazyErrorMark | boolean | 延迟错误标记 | false | | forceRender | boolean | 强制渲染所有标签页 | false | | keepSerial | boolean | 保持连续编号 | false | | loading | boolean | 加载状态 | false | | max | number | 最大项目数量 | Infinity | | itemMenus | GroupMenuItem[] | 自定义菜单项 | 默认复制/删除 | | createItem | (opts: { list: T[] }) => Promise<T> | 自定义项目创建器 | - | | menuHandler | GroupMenuItemHandler<T> | 自定义菜单处理器 | - |

暴露的方法

| 方法 | 说明 | 参数 | 返回值 | | --- | --- | --- | --- | | validateAll | 验证所有表单实例 | - | Promise<void> | | validate | 验证特定表单实例 | __index: number | Promise<void> | | setActiveKey | 设置活动标签页 | key: number | void |

基础示例

<script setup lang="ts">
import { ref, computed } from 'vue';
import { PFormGroupProps } from '@vue-ui-kit/ant';

interface Project {
  __index: number;
  name: string;
  startDate: string;
  endDate: string;
  budget?: number;
}

const projects = ref<Project[]>([
  {
    __index: 0,
    name: '项目A',
    startDate: '',
    endDate: '',
    budget: undefined,
  }
]);

const groupSetting = computed<PFormGroupProps<Project>>(() => ({
  title: '项目管理',
  showAdd: true,
  max: 10,
  getFormSetting: (data) => ({
    items: [
      {
        field: 'name',
        title: '项目名称',
        span: 24,
        rule: [{ required: true, message: '请输入项目名称' }],
        itemRender: {
          name: '$input',
          props: { placeholder: '请输入项目名称' },
        },
      },
      {
        field: 'startDate',
        title: '开始日期',
        span: 12,
        rule: [{ required: true, message: '请选择开始日期' }],
        itemRender: {
          name: '$date',
          props: { placeholder: '请选择开始日期' },
        },
      },
      {
        field: 'endDate',
        title: '结束日期',
        span: 12,
        rule: [{ required: true, message: '请选择结束日期' }],
        itemRender: {
          name: '$date',
          props: { placeholder: '请选择结束日期' },
        },
      },
      {
        field: 'budget',
        title: '预算',
        span: 24,
        itemRender: {
          name: '$number',
          props: {
            min: 0,
            placeholder: '请输入预算',
            formatter: (value) => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ','),
            parser: (value) => value.replace(/¥\s?|(,*)/g, ''),
          },
        },
      },
    ],
  }),
}));

const handleSave = async () => {
  try {
    await groupRef.value?.validateAll();
    console.log('所有项目已保存:', projects.value);
  } catch (error) {
    console.error('验证失败:', error);
  }
};

const groupRef = ref();
</script>

<template>
  <div>
    <p-form-group 
      ref="groupRef"
      v-model="projects"
      v-bind="groupSetting"
    />
    <a-button type="primary" @click="handleSave">
      保存所有项目
    </a-button>
  </div>
</template>

自定义菜单示例

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

const projects = ref([]);

const groupSetting = computed(() => ({
  title: '高级项目管理',
  itemMenus: [
    { content: '复制', code: 'copy' },
    { content: '删除', code: 'delete' },
    { content: '导出', code: 'export' },
    { 
      content: '归档', 
      code: 'archive',
      visibleMethod: ({ data }) => data.status !== 'archived'
    },
  ],
  createItem: async ({ list }) => {
    return {
      name: `项目 ${list.length + 1}`,
      status: 'active',
      startDate: new Date().toISOString().split('T')[0],
    };
  },
  menuHandler: ({ code, data, index }) => {
    switch (code) {
      case 'export':
        exportProject(data);
        break;
      case 'archive':
        archiveProject(data, index);
        break;
    }
  },
  getFormSetting: (data) => ({
    // ... 表单配置
  }),
}));
</script>

工具函数

labelColDict

为不同文本长度预定义的标签列配置:

import { labelColDict } from '@vue-ui-kit/ant';

// 在表单项中使用
{
  field: 'shortField',
  title: '姓名', // 2个字符
  labelCol: labelColDict[2],
}

{
  field: 'longerField', 
  title: '项目描述', // 4+个字符
  labelCol: labelColDict[4],
}

自定义渲染器

注册自定义表单字段渲染器:

import UIKit from '@vue-ui-kit/ant';
import { Switch } from 'ant-design-vue';

UIKit.addRender('$switch', {
  renderItemContent(
    { props = {}, events = {} },
    { data, field }
  ) {
    return (
      <Switch
        v-model:checked={data[field]}
        {...props}
        onChange={(...args) => {
          events.change?.({ data, field }, ...args);
        }}
      />
    );
  },
});

自定义格式化器

为 PGrid 注册自定义单元格格式化器:

UIKit.addFormatter({
  currency: ({ cellValue }) => `¥${cellValue?.toLocaleString() || '0'}`,
  percentage: ({ cellValue }) => `${(cellValue * 100).toFixed(2)}%`,
});

常见问题

1. 使用 computed + v-bind 生成动态表格+表单时,表单选项更新导致表格重新渲染,如何解决?

答案:将 formConfig 分离为另一个计算属性

<p-grid v-bind="gridSetting" :form-config="computedFormConfig" />

2. 表格 ajax 目前只支持 multiDelete 和表格数据获取吗?

答案:编辑详情在大多数情况下无法与表格一一对应,所以没有开发意义。多行删除需要配合使用:

selectConfig: {
  multiple: true,
},
toolbarConfig: {
  buttons: {
    code: "multipleDelete"
  }
}

3. 为什么推荐 computed 方式?

答案:它简化了所有动态逻辑。对于复杂场景,您可以尝试使用 reactive 并自己维护,但在大多数情况下,computed 更方便。

TypeScript 支持

该库完全使用 TypeScript 编写,并提供全面的类型定义:

import type { 
  PFormProps, 
  PFormItemProps,
  PFormGroupProps,
  PGridProps,
  ColumnProps 
} from '@vue-ui-kit/ant';

许可证

MIT