vue-formless
v0.2.0
Published
Vue 3 表单组合式 hooks
Maintainers
Readme
vue-formless
简体中文 | English
Vue 3 表单组合式库:控件表 + FormView,布局与输入拆开。当前 0.2.0,
0.x期间 API 仍可能调整。
同一套混合布局:左边手写 Element Row/Col/Item,右边 <User.*> + 嵌套 FormView 换密度。

Playground 平铺对比(布局对齐):

pnpm add vue-formless
# 或 npm i vue-formlesspeer:vue ^3.3。
用法
项目里绑一次宿主(无官方 Element 适配包):
import { ElCol, ElForm, ElFormItem, ElInput, ElRow } from 'element-plus'
import { defineComponent, h, ref, type PropType } from 'vue'
import { createFormFields, createFormView, type FormFieldFormless } from 'vue-formless'
declare module 'vue-formless' {
interface FormFieldCustomOptions {
label?: string
}
}
// ElFormItem 的 `prop` 用点分路径;内核位置(`buyers[0].name`)由本层编码(design.md §20.9)。
// 一个宿主 `prop` 装不下多个口 → 多口一格不绑宿主(`undefined`),
// 需要宿主校验就用 `fl:field="wrap-embed"` 拆成一格一口。
function toItemProp(prop: FormFieldFormless['prop']): string | undefined {
if (prop == null || prop.length !== 1) return undefined
const [location] = prop
if (location == null) return undefined
const dotted = location.replace(/\[(\d+)\]/g, '.$1').replace(/^\./, '')
if (!dotted || /[[\]]/.test(dotted)) return undefined // 编不出来:不绑宿主
return dotted
}
// 无前缀的写口 `modelValue` 按 no-prefix 规则透传到宿主 Form,而 ElForm 的 model
// 口叫 `model`:适配层用一个 MyForm 包住 ElForm 完成映射,并把 ElForm 实例的
// validate / resetFields 透出给 FormView 的 ref 代理。工厂不再接受 form.props 函数。
const MyForm = defineComponent({
inheritAttrs: false,
props: { modelValue: { type: [Object, Array] as PropType<unknown>, default: undefined } },
setup(props, { attrs, slots, expose }) {
const form = ref<Record<string, unknown> | null>(null)
expose(new Proxy({}, {
get: (_, key) => {
const inner = form.value
if (inner == null) return undefined
const value = Reflect.get(inner, key, inner)
return typeof value === 'function' ? value.bind(inner) : value
},
has: (_, key) => form.value != null && key in form.value,
}))
return () => h(ElForm, { ...attrs, ref: form, model: props.modelValue }, slots)
},
})
export const FormView = createFormView({
layout: { Row: ElRow, Col: ElCol, props: { column: 2 } },
form: { component: MyForm },
item: {
component: ElFormItem,
props: (fl: FormFieldFormless) => ({
label: fl.label,
prop: toItemProp(fl.prop),
}),
},
})
export const User = createFormFields({
name: { label: '姓名', component: ElInput },
})<FormView ref="formRef" v-model="form" fl:layout label-width="96px">
<User.Name />
<User.Name layout-item:span="max" />
</FormView>validate() / resetFields() 走 FormView 的 ref(代理内层 Form)。栅格细节见 docs/adr。
在线 Playground
GitHub Pages(仓库需在 Settings → Pages → Source 选 GitHub Actions,推 main 后生成):
- 表单对照:https://xuyimingwork.github.io/vue-formx/
- 24 格布局:https://xuyimingwork.github.io/vue-formx/layout/
本地预览打包结果:PAGES_BASE=/vue-formx/ pnpm build:pages,再用任意静态服务器打开 site/。
仓库结构
packages/vue-formless # 内核(npm:vue-formless)
packages/layout # 内部栅格,打进内核 dist
playground # Element Plus 基线 vs Formless
playground-layout # 24 格布局工作台
docs/adr.md # 架构决策(单篇汇总)开发
pnpm i
pnpm dev # 启动 playground
pnpm build # 构建库
pnpm test
pnpm typecheckPlayground 对照:基础表单、筛选条、只读详情、混合布局、DateRange。
pnpm playground
# http://localhost:5173
pnpm playground:layout
# http://localhost:5174