cl-form

自定义表单组件

  • @cool-vue/crud@6.x 新增 ref 参数,方便获取组件实例

useForm()

cl-form 标签绑定 ref 值后使用 useForm 加载组件

  • const 定义必须与 ref 一致
<template>
	<cl-form ref="Form"></cl-form>
</template>

<script lang="ts" setup>
	import { useForm } from "@cool-vue/crud";
	const Form = useForm();
</script>

如果存在使用多个 cl-form 组件的情况,配置不同的 ref 值即可:

<template>
	<cl-form ref="UserForm"></cl-form>
	<cl-form ref="GoodsForm"></cl-form>
</template>

<script lang="ts" setup>
	import { useForm } from "@cool-vue/crud";
	const UserForm = useForm();
	const GoodsForm = useForm();
</script>

TIP

子组件可以也可以使用 const Form = useForm() 获取 cl-form 实例。同样 Ref 上的值与方法都能使用

<template>
	<cl-form ref="Form"></cl-form>
</template>

<script lang="ts" setup>
	import { useForm } from "@cool-vue/crud";
	const Form = useForm();

	function open() {
		Form.value.open({
			items: [
				{
					label: "昵称",
					prop: "name",
					component: {
						vm: Test
					}
				}
			]
		});
	}
</script>

Test.vue

<template>
	<!-- 绑定name -->
	<el-input v-model="Form.form.name" />
</template>

<script lang="ts" setup>
	import { useForm } from "@cool-vue/crud";
	const Form = useForm();
</script>

示例

基础用法

分组显示

配置 type 参数为 tabslabels 作为分组列表:

  • label 分组名称
  • value 分组标识

获取组件实例

在部分情况下,想要获取到组件的实例,有 2 种方法:

  • ref 参数
const { refs, setRefs } = useCool();

const Form = useForm({
	items: [
		{
			label: "昵称",
			prop: "name",
			component: {
				name: "el-input",
				ref: setRefs("name")
			}
		}
	],
	on: {
		open() {
			refs.name.focus();
		}
	}
});
  • 插槽
<cl-form ref="Form">
	<template #slot-name="{ scope }">
		<el-input :ref="setRefs('name')" v-model="scope.name" />
	</template>
</cl-form>

钩子函数

  • open(data) 打开后

  • close(done) 关闭前

  • submit(data, { close, done }) 提交时

参数

参数说明类型可选值默认值
inner是否只显示表单booleanfalse
inline是否内联表单booleanfalse

Ref

方法名说明参数
form表单值
open打开表单Options
close关闭表单
done关闭 saving 状态
clear清空表单值
reset重置表单值
showLoading显示加载框
hiddenLoading隐藏加载框
setTitle设置标题title
setData根据对象层级设置参数prop, value
setOptions设置下拉列表prop, value
setProps设置组件参数prop, props
getForm获取表单值prop?
setForm设置表单值prop, value
toggleItem切换 hidden 值prop, flag?
hideItem隐藏props
showItem显示props
resetFields对整个表单进行重置
clearValidate移除表单项的校验结果props: array / string
validateField对部分表单字段进行校验的方法props: array / string, callback
validate对整个表单进行校验的方法callback
changeTab切换选项栏name
submit表单提交callback(data)

OpenOptions

参数说明类型可选值默认值
title标题string
width宽度string
items表单项Items
propsel-form 参数FormProps
form表单值object
on事件监听object
on.open表单打开function(form)
on.close表单关闭function(done)
on.submit表单提交function(data, {close,done})
dialog对话框参数object
dialog.hiddenHeader隐藏头部booleanfalse
dialog.controls头部操作按钮array["fullscreen", "close"]
op底部操作按钮object
op.hidden是否隐藏booleanfalse
op.saveButtonText保存按钮文案string保存
op.closeButtonText关闭按钮文案string取消
op.buttons按钮组array["close", "save"]

FormProps

参数说明类型可选值默认值
inline行内表单模式booleanfalse
label-width表单域标签的宽度string120px
label-position表单域标签的位置stringleft / top / rightright
label-suffix表单域标签的后缀string
hide-required-asterisk是否显示必填字段的标签旁边的红色星号booleanfalse
show-message是否显示校验错误信息booleantrue
inline-message是否以行内形式展示校验信息booleanfalse
status-icon是否在输入框中显示校验结果反馈图标booleanfalse
validate-on-rule-change是否在 rules 属性改变后立即触发一次验证booleantrue
size用于控制该表单内组件的尺寸stringlarge / default /smalldefault
disabled是否禁用该表单内的所有组件booleanfalse

Items

参数说明类型可选值默认值
type类型stringtabs
prop字段string
value默认值,对应组件 componentv-modelany
props对应 component 组件的 prop 参数object
label标签文本string, RenderOptions
component组件渲染object
component.name组件标签名、 slot 名string
component.vm组件渲染节点object
component.style组件样式object
component.props组件参数object
component.ref组件绑定值setRefs(string)
prepend添加到 component 组件前object
append添加到 component 组件后object
collapse是否折叠boolean
rules验证规则array, object
required是否必填,自动填充 rulesbooleanfalse
hidden是否隐藏boolean, string, functionfalse
span栅格占据的列数number24
flex是否横向拉升元素booleantrue
group分组显示string
hook钩子模式array / string / object / function
hook.bind表单值绑定时触发数据更新array / string / object / function
hook.submit表单提交时触发数据更新array / string / object / function

TIP

  1. 静态配置
const Form = useForm();

Form.value?.open({
	items: [
		{
			label: "昵称",
			prop: "nickName",
			component: {
				name: "el-input"
			}
		}
	]
});
  1. 动态配置,如在 upsert 中新增、编辑显示不同的状态
const Form = useForm();

Form.value?.open({
	items: [
		({ scope }) => {
			// scope 表单值
			return {
				label: "昵称",
				prop: "nickName",
				component: {
					name: "el-input"
				}
			};
		}
	]
});

Component

表单项的元素通过 component 渲染,该参数支持 4 中渲染方式:

  1. 绑定标签
  • 该组件必须是全局注册

  • 该方式会自动绑定组件的 v-model

  • props 为该组件参数

  • el-select el-checkbox-group el-radio-group 支持配置列表数据 options

Form.value?.open({
	items: [
		{
			label: "昵称",
			prop: "name",
			component: {
				name: "el-input",
				props: {
					clearable: true
				}
			}
		}
	]
});
Form.value?.open({
	items: [
		{
			label: "职业",
			prop: "work",
			component: {
				name: "el-select",
				options: [
					{
						label: "程序员",
						value: 0
					},
					{
						label: "设计师",
						value: 1
					}
				]
			}
		}
	]
});
  1. 万能插槽,适用于各种场景
  • 必须以 slot- 开头命名

  • scope 为表单值

Form.value?.open({
	items: [
		{
			label: "昵称",
			prop: "name",
			component: {
				name: "slot-name"
			}
		}
	]
});
<cl-form>
	<template #slot-name="{ scope }">
		<el-input v-model="scope.name" />
	</template>
</cl-form>
  1. 使用 tsx 标签渲染
  • lang 必须为 tsx

  • 这种方式下无法绑定 v-model

<script lang="tsx" setup>
	Form.value?.open({
		items: [
			{
				label: "昵称",
				prop: "name",
				component: <el-alert title="无效昵称" />
			}
		]
	});
</script>
  1. 使用 .vue.tsx 文件或者 render 方法
  • 绑定在 vm

  • 该方式会自动绑定组件的 v-model,但是需要自己处理 update:modelValue 值的接收及更新

  • props 为该组件参数

Form.value?.open({
	items: [
		{
			label: "昵称",
			prop: "name",
			component: {
				vm: {
					name: "test-name",
					// 接收值
					props: {
						modelValue: String
					},
					setup(props: any, { emit }: any) {
						const value = ref<string>();

						// 监听值变化,如果在 cl-upsert 下,第一次会为 undefined
						watch(
							() => props.modelValue,
							(val) => {
								value.value = val;
							},
							{
								immediate: true
							}
						);
						return {
							value,
							// 更新值
							onInput(val: string) {
								emit("update:modelValue", val);
							}
						};
					},
					render(ctx: any) {
						// 绑定值
						return <el-input v-model={ctx.value} onInput={ctx.onInput} />;

						// 也可以使用 h 的方式渲染
						// return h(resolveComponent('el-input'))
					}
				}
				props: {
					type: "a"
				}
			}
		}
	]
});
import Test from "./test.vue";

Form.value?.open({
	items: [
		{
			label: "昵称",
			prop: "name",
			component: {
				vm: Test,
				props: {
					type: "a"
				}
			}
		}
	]
});

Hook

该参数设计于为了更方便的接收、提交参数。

当有这么一个场景,后端返回给你的 idList 是用 , 拼接的,如:

{
	idList: "1,2,3";
}

前端是需要你用 el-select 的组件展示,且需要多选模式 multiple。那一般的操作都是获取数据后对数据 split 分割,再绑定于 value 上。

这时候就可以用到 hook 参数,它可以在绑定 value 的时候预先处理数据:

{
	label: '角色列表',
	prop: 'ids',
	hook: {
		bind: ['split', 'number'], // 通道流程,分割 -> 转成number -> 绑定值
	},
	component: {
		name: 'el-select',
		props: {
			multiple: true
		},
		options: [
			{
				label: "李逍遥",
				value: 1
			},
			{
				label: "景天",
				value: 2
			},
			{
				label: "宇文拓",
				value: 3
			}
		]
	}
}

// 绑定的数据:
{
	ids: [1, 2, 3]
}

当然有些 讨厌 的后端又想让你以 1,2,3 逗号拼接的方式提交。那你也可以用 hook 参数处理,用 join 的方式拼接:

{
	label: '角色列表',
	prop: 'ids',
	hook: {
		bind: ['split', 'number'],  // 绑定通道流程,分割 -> 转成number -> 绑定值
		submit: ['join'],	// 提交通道流程,逗号拼接 -> 提交
	},
	component: {
		name: 'el-select',
		props: {
			multiple: true
		},
		options: [
			{
				label: "李逍遥",
				value: 1
			},
			{
				label: "景天",
				value: 2
			},
			{
				label: "宇文拓",
				value: 3
			}
		]
	}
}

// 提交的数据:
{
	ids: '1,2,3'
}

hook 已有的方法

名称说明
number转成 number, 如果值是数组,那每一项都会被操作到
string转成 string, 如果值是数组,那每一项都会被操作到
split字符串以 , 分割为数组
join数组以 , 拼接为字符串
boolean转成 boolean
booleanNumber接收一个 boolean 值,返回 1 或 0
datetimeRange在提交中会根据 prop 自动转换为 start[prop]end[prop]
splitJoin绑定时 split(","),提交时 join(",")
json绑定时 JSON.parse(),提交时 JSON.stringify()
empty等于""时修改为 undefined

当然你也可以用自定义:

// 例如 value 为:"1,2,3"
{
	hook: {
		bind: (value, form) => {
			// value 是与 prop 绑定的值
			// form 是表单值

			return value.split(",").map(Number).filter(Boolean); // 结果为:[1, 2, 3]
		},
		submit: (value, form) => {
			return value.join(","); // 结果为:"1,2,3"
		}
	}
}

也可以多个处理:

hook: {
	bind: [
		'split', // 1 分割
		() => {
			// 2 自定义
		},
		'number', // 3 转成 number
	],
	submit: [
		'join', // 1 拼接
		() => {
			// 2 自定义
		}
	]
}

Hidden

// 默认填入 boolean
{
	label: "姓名",
	prop: "name",
	hidden: false
}

// scope 为表单数据,自定义返回值
{
	label: "姓名",
	prop: "name",
	hidden: ({ scope }) => {
		return !scope.showName
	}
}

// 使用 ref
const isHidden = ref(false)

{
	label: "姓名",
	prop: "name",
	hidden: isHidden
}

// 使用 computed
const isHidden = computed(() => false)

{
	label: "姓名",
	prop: "name",
	hidden: isHidden
}
Last Updated: