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

@shaonq/vue

v1.6.1

Published

shaonq Vue Library

Readme

@shaonq/vue

Vue 3 组件库:OrcTable(vxe-table 封装)、OrcForm(配置驱动动态表单)、OrcSearch(搜索栏)。

ColBuilder 配置构建器

ColBuilder 用于以最少的代码构建 orc-table 列配置(OrcTableItem)与 orc-form 表单项配置(OrcFormItem),消除 type/model/name 与深层嵌套(OrcFormTable / OrcFormLayer)的样板代码。

import { ColBuilder } from '@shaonq/vue';

表格列(orc-table / orc-search)

| 方法 | 签名 | 说明 | | ----------------- | ----------------------------------------------- | ------------------------------------------------------------ | | tableItem | (dataIndex, title?, overrides?) | 通用列。overrides.dataType 自动附带默认列宽 | | tableItemStatus | (dataIndex, title, texts?, size?, overrides?) | 状态标签列(Tag 渲染),texts 为 { value, label, color }[] |

ColBuilder.tableItem('name', '姓名', { dataType: 'string' });
ColBuilder.tableItem('amount', '金额', { dataType: 'number', align: 'right' });
ColBuilder.tableItem('other'); // 占位操作列

ColBuilder.tableItemStatus('status', '状态', [
  { value: '1', label: '启用', color: 'green' },
  { value: (v) => !v, label: '空', color: 'gray' }, // value 支持函数
]);

表单项(orc-form config)

| 方法 | 签名 | 说明 | | ----------- | ------------------------------------ | --------------------------------------------------------------------------- | | formItem | (model, name?, overrides?) | 通用表单项。overrides.props 与 componentAttr 合并透传组件属性 | | formTable | (model, name, columns, opts?) | 子表格(OrcFormTable)。columns 为列配置(继续用 formItem) | | formLayer | (model, name, tableOptions, opts?) | 弹窗选行(OrcFormLayer)。tableOptions 为表格配置,columns 用 tableItem |

// 基础表单项
ColBuilder.formItem('name', '姓名', { type: 'a-input', options: { required: true } });
ColBuilder.formItem('role', '角色', {
  type: 'a-select',
  options: { required: true },
  defaultValue: '1',
  props: { allowClear: true },
  events: { onMounted: () => [{ label: '管理员', value: '1' }] }, // 异步选项
});

// 子表格(OrcFormTable):列配置用 formItem
ColBuilder.formTable(
  'list',
  '不合格明细',
  [
    ColBuilder.formItem('F_BadId', '不合格原因', { type: 'a-select' }),
    ColBuilder.formItem('F_Qty', '数量', { type: 'a-input-number' }),
    ColBuilder.formItem('other'),
  ],
  {
    span: 24, // 栅格宽度
    required: true, // 表单项必填
    defaultValue: [], // 缺省 []
    height: 200, // 表格高度
    hideTools: false,
    tableOptions: { rules: { F_Qty: [{ type: 'number', min: 10, message: '数量必须≥10' }] } }, // 行编辑校验
  }
);

// 弹窗选行(OrcFormLayer):表格配置用 OrcTableOption,列用 tableItem
ColBuilder.formLayer(
  'holiday',
  '选择假期',
  {
    selectedType: 'radio',
    scrollX: { enabled: true },
    scrollY: { enabled: true },
    columns: [ColBuilder.tableItem('date', '日期', { dataType: 'date' }), ColBuilder.tableItem('name', '假日名称', { dataType: 'string' })],
  },
  {
    span: 24,
    required: true,
    pagination: true,
    nameKey: 'name', // 回显字段,缺省 'name'
    tableData: [], // 静态数据(不走接口时)
  }
);

输出结构(等价手写配置)

  • formTable → { type: OrcFormTable, model, name, options: { span, required }, defaultValue: [] , componentAttr: { ...剩余项, options: columns } }
  • formLayer → { type: OrcFormLayer, model, name, options: { span, required }, componentAttr: { ...剩余项, options: tableOptions } }
  • formItem → 字段分发:options/defaultValue/events 保持原结构,props 与 componentAttr 合并到 componentAttr

注意(formTable / formLayer):

  • 字段级 events.onChange 对 OrcFormTable 不生效(子表格不 emit change 事件)。行内联动请写在列配置的 events.onChange 上(参数为 [value, { rowIndex, row }])
  • OrcFormLayer 的 events.onChange 参数是 { name, data } 对象而非新值(与普通字段不同),联动建议直接用 util.getModel(...)
  • componentAttr 中的函数属性(如 disabled)每次渲染执行两次,请保持为纯函数(无请求/计数副作用)

OrcTable 树形表格

orc-table 继承 vxe-table,通过 option.treeConfig 与列的 treeNode 开启树形结构(treeConfig 即 vxe 的 tree-config)。

| 配置 | 类型 | 说明 | | ---------------------- | --------- | ------------------------------------------------------------------------- | | option.treeConfig | object | { transform: true, rowField: 'id', parentField: 'parentId' } 等原生配置 | | option.checkStrictly | boolean | 复选框关闭父子联动 | | columns[].treeNode | boolean | 标记展开图标所在列 |

<orc-table
  :data="list"
  :option="{
    rowKey: 'id',
    treeConfig: { transform: true, rowField: 'id', parentField: 'parentId', expandAll: true },
    columns: [
      { dataIndex: 'name', title: '名称', treeNode: true, width: 260 },
      { dataIndex: 'amount', title: '金额', width: 120, align: 'right' },
    ],
  }"
/>
  • transform: true 时传扁平数据(含 parentId),由 vxe 自动转成树;根节点 parentId 置空
  • transform: false 时传嵌套数据(children)
  • rowKey 需与 treeConfig.rowField 一致
  • option.tableProps 优先级最高,会覆盖 treeConfig

OrcForm 替换 a-form 使用指南

OrcForm 内部就是 a-form + a-row + a-col + a-form-item 的封装,把「模板 + v-model + rules」改写成「一个 config 数组」。数据绑定、校验、提交、禁用、联动全部由配置驱动,模板只剩一行。

1. 对比示例

a-form 写法(模板 20 行)

<a-form ref="formRef" :model="formData" :rules="rules" :label-col-props="{ flex: '110px' }" label-align="right" size="small">
  <a-row :gutter="8">
    <a-col :span="12">
      <a-form-item field="name" label="姓名" :rules="[{ required: true, message: '请输入姓名' }]">
        <a-input v-model="formData.name" placeholder="请输入姓名" allow-clear />
      </a-form-item>
    </a-col>
    <a-col :span="12">
      <a-form-item field="role" label="角色">
        <a-select v-model="formData.role" :options="roleOptions" placeholder="请选择角色" allow-search />
      </a-form-item>
    </a-col>
  </a-row>
  <a-form-item>
    <a-button type="primary" html-type="submit">提交</a-button>
  </a-form-item>
</a-form>

orc-form 等价写法(config 一份 + 模板一行)

import { OrcForm, ColBuilder } from '@shaonq/vue';
import type { OrcFormItem } from '@shaonq/vue';

const roleOptions = [
  { label: '管理员', value: '1' },
  { label: '用户', value: '2' },
];

const config: OrcFormItem[] = [
  ColBuilder.formItem('name', '姓名', {
    type: 'a-input',
    options: { required: true }, // 自动生成必填规则 + 红星
    props: { allowClear: true }, // 组件属性透传(等价 v-bind)
  }),
  ColBuilder.formItem('role', '角色', {
    type: 'a-select',
    defaultValue: '1',
    props: { options: roleOptions, allowSearch: true }, // 组件属性(含数据源)
  }),
];
<orc-form v-model="formData" :config="config" @submit="onSubmit" />

2. 属性映射表

| a-form 写法 | orc-form 写法 | | ---------------------------------------- | ------------------------------------------------------------------------- | | :model="formData" + 每个控件 v-model | v-model="formData" 整体绑定,控件 v-model 自动完成 | | 整表 :rules="rules" | 每个字段 options.required 或字段级 rules | | :label-col-props="{ flex: '110px' }" | label-width="110px" | | label-align="right" | label-align="right"(默认 right) | | size="small" | 固定 small,不需要写 | | <a-row :gutter="8"> | :gutter="8"(默认 8) | | <a-col :span="12"> | 字段 options.span: 12(或组件级 :span 全局默认) | | <a-form-item field="xxx"> | 字段 model: 'xxx' | | <a-form-item label="xxx"> | 字段 name: 'xxx' | | <a-form-item :disabled> | 字段 options.disabled 或组件 :disabled | | <a-form-item :help> | 字段 options.help | | <a-form-item :tooltip> | 字段 options.tooltip | | <a-form-item :validate-trigger> | 字段 validateTrigger | | <a-form-item :label-col-flex> | 字段 itemAttr: { labelColFlex: ... } | | 控件 placeholder | 字段 options.placeholder,不写自动「请输入 / 请选择」 | | 控件其余 props | 字段 componentAttr(ColBuilder 中写 props 同义) | | 自定义提交按钮 | 组件自带「保存」按钮(hide-submit 可隐藏,#row 插槽可替换) | | @submit(需 ev.preventDefault()) | @submit="({ data, utils }) => ...",校验通过才触发,无需 preventDefault |

3. 校验

// 必填:options.required 自动生成 [{ required: true, message: '请输入/请选择xxx' }]
{ type: 'a-input', model: 'name', name: '姓名', options: { required: true } }

// 自定义规则:字段级 rules(支持 Arco 全部规则,或返回规则数组的函数)
{
  type: 'a-input-number', model: 'qty', name: '数量',
  rules: [{ type: 'number', min: 10, max: 100, message: '数量必须在 10 ~ 100 之间' }],
}

// 触发时机
{ type: 'a-input', model: 'code', name: '编码', validateTrigger: 'blur' }

提交时自动校验全部字段;未通过则触发 @error 且不触发 @submit。也可用 ref 手动校验:

const formRef = ref(); // <orc-form ref="formRef" />
const [err, data] = await formRef.value.onSubmit(); // err 为空表示通过

4. 提交与重置

function onSubmit({ data, utils }: OrcFormSubmit) {
  utils.setLoading(true); // 保存按钮转圈
  try {
    await saveApi(data); // data 为校验通过后的表单数据
    utils.resetFields(); // 重置字段(或调 ref.onReset())
    Message.success('保存成功');
  } finally {
    utils.setLoading(false);
  }
}
  • utils.setLoading(true/false) — 保存按钮 loading
  • utils.resetFields() — 清空字段
  • ref 方法:formRef.value.onSubmit()(校验+提交)、onReset()(恢复 defaultValue)、resetFields()(清空)
  • 弹窗模式(OrcFormButton)额外有 utils.setVisible(true/false)

5. 动态交互(替换原来的 watch / 手动赋值)

| 需求 | a-form 做法 | orc-form 做法 | | ------------------ | ------------------------- | ----------------------------------------------------------------------------- | | 下拉选项异步加载 | onMounted 请求后赋值 | 字段 events.onMounted: () => options数组 | | 字段联动显示/隐藏 | v-if + watch 手动控制 | events.onChange 里 util.setShow(model, bool) | | 字段联动赋值 | 手动 formData.xxx = ... | util.setModel('xxx', val) 或 util.setModel({a: 1}) | | 读取字段值 | formData.xxx | util.getModel('xxx') / util.getModels() | | 动态切换下拉选项 | 手动改 roleOptions | util.setModelOption('role', newOptions) | | 控件属性随状态变化 | computed props | componentAttr: { disabled: (util) => util.getModel('type') === 'readonly' } | | 值变化监听 | @change 逐个绑定 | 字段 events.onChange: (val, util) => ... |

// 联动示例:切换「类型」后,动态显示/隐藏字段并重新加载选项
ColBuilder.formItem('type', '类型', {
  type: 'a-select',
  options: { required: true },
  events: {
    onMounted: () => [{ label: 'A', value: 'a' }, { label: 'B', value: 'b' }],
    onChange(val, util) {
      util.setShow('code', val === 'a'); // 显示/隐藏
      util.setModelOption('role', val === 'a' ? [{ label: 'x', value: '1' }] : []); // 切换选项
    },
  },
}),

6. 常用字段速查

ColBuilder.formItem('name', '姓名', { type: 'a-input' }); // 文本框
ColBuilder.formItem('remark', '备注', { type: 'a-textarea', props: { maxLength: 200, showWordLimit: true } });
ColBuilder.formItem('qty', '数量', { type: 'a-input-number', props: { min: 0, max: 100 } });
ColBuilder.formItem('date', '日期', { type: 'a-date-picker' });
ColBuilder.formItem('datetime', '时间', { type: 'a-date-picker', props: { showTime: true } });
ColBuilder.formItem('switch', '启用', { type: 'a-switch', defaultValue: true });
ColBuilder.formItem('role', '角色', { type: 'a-select', props: { options: roleOptions, allowSearch: true } });
ColBuilder.formItem('sex', '性别', {
  type: 'a-radio-group',
  defaultValue: 'male',
  props: {
    options: [
      { label: '男', value: 'male' },
      { label: '女', value: 'female' },
    ],
  },
});
ColBuilder.formItem('dept', '部门', { type: 'a-tree-select', props: { treeData: [], allowSearch: true } });

7. 复杂字段(替代自定义封装)

| 场景 | 用法 | | -------------------------- | ----------------------------------------------------------------------------------------------------------------- | | 子表格(行内编辑) | ColBuilder.formTable(model, name, 列config, opts) — 见上文 ColBuilder 章节 | | 弹窗选行(TablePicker 类) | ColBuilder.formLayer(model, name, tableOptions, opts) — 见上文 ColBuilder 章节 | | 自定义组件 | type: 组件对象(如 defineAsyncComponent),自动注入 modelValue / update:modelValue / utils 实现 v-model | | 覆盖默认控件渲染 | 插槽 <template #model名="{ value, setValue, options, utils }"> |

字典类下拉(字典数据经 events.onMounted 异步加载选项,配合 util.setModelOption 可动态刷新):

// config 中:挂载时加载字典选项
{
  type: 'a-select', model: 'status', name: '状态',
  events: {
    onMounted: async (util) => {
      const list = await fetchDict('order-status'); // 自行实现字典请求
      util.setModelOption('status', list);
    },
  },
}

8. 弹窗表单(替换 a-modal + a-form + 按钮)

<orc-form-button title="新增用户" :config="config" @submit="onSubmit">
  <a-button>新增</a-button>
</orc-form-button>
// @submit 回调:校验通过后触发,utils 额外支持 setVisible
function onSubmit({ data, utils }: OrcFormSubmit) {
  utils.setLoading(true);
  await saveApi(data);
  utils.setLoading(false);
  utils.setVisible(false); // 关闭弹窗
}

常用 props:title(弹窗标题)、config、modelValue(回显数据)、labelWidth、disabled、isView(只读展示模式)、buttonAttrs(按钮属性)、modalAttrs(弹窗属性)、span/gutter。

9. 常见坑

  • 字段 options.span 缺省继承组件 :span(默认 24 即整行);想一行放多个字段记得配 span
  • componentAttr 中函数属性(如 disabled)在渲染时执行,入参 util,可做跨字段联动;保持纯函数(每次渲染执行两次,勿放请求/计数副作用)
  • 非字符串 type(自定义组件)会自动绑定 v-model,不要重复传 modelValue
  • 不要给 type 传 'a-form'/'a-form-item' 这类容器组件,容器由 OrcForm 统一管理
  • hide-submit 隐藏保存按钮后,仍可用 ref.onSubmit() 触发校验提交
  • 子表格行内联动:在列配置的 events.onChange 中 setModel 修改整行数据时,组件随后会基于旧数据回写当前列,可能覆盖联动结果。推荐写法:
// 行内联动(子表格列配置):先拿到当前行,改完后整体 setModel 刷新
ColBuilder.formItem('adjust', '调整金额', {
  type: 'a-input-number',
  events: {
    onChange([val, { rowIndex, row }], util) {
      const list = util.getModel('tableData'); // 从表单模型取整表
      list[rowIndex] = { ...row, adjust: val, status: val > 3000 ? '待审核' : '已确认' };
      util.setModel('tableData', [...list]); // 整体覆盖,避免组件旧数据回写覆盖
    },
  },
}),

本地命令

lerna clean    # 从所有包中删除 node_modules
lerna publish  # 发布
lerna link     # 关联包,模拟发布后的效果
lerna ls       # 查看本地包列表