vue3 组件-表单组件
该组件依赖element-plus
。
典型表单
查看代码
vue
<template>
<KForm
:options="options"
@submit="submit"
@submit-check-fail="submitCheckFail"
/>
</template>
<script setup lang="ts">
import { ref } from "vue"
import type { FormProps } from "@tomiaa/vue3-components"
import { KForm } from "@tomiaa/vue3-components"
// 活动标签列表,模拟异步数据
const tag = ref("")
const selectTagData = ref<FormProps["options"]>([])
setTimeout(() => {
selectTagData.value = [
{
el: "el-option",
label: "标签一",
value: "one",
},
{
el: "el-option",
label: "标签二",
value: "two",
},
]
tag.value = selectTagData.value[0].value
}, 5000)
// 表单配置,FormProps["options"] 声明以获取更好的 TS 类型提示
const options = ref<FormProps["options"]>([
{
el: "el-input",
label: "活动名称",
prop: "name",
modelValue: "这是双向绑定的值,也是默认值", // 存在 modelValue 时 prop 字段必填,否者值不会同步
},
{
el: "el-select",
label: "活动地点",
prop: "zone",
children: [
{
el: "el-option",
label: "上海",
value: "shanghai",
},
{
el: "el-option",
label: "北京",
value: "beijing",
},
],
rules: [
{
required: true,
message: "必填",
},
],
},
{
el: "el-select",
label: "活动标签",
prop: "tag",
// 可以是 ref 对象
modelValue: tag,
children: selectTagData,
},
{
el: "el-date-picker",
prop: "startDate",
label: "开始时间",
span: 12,
},
{
el: "el-date-picker",
prop: "endDate",
label: "结束时间",
span: 12,
},
{
el: "el-switch",
prop: "instantDelivery",
label: "状态",
span: 4,
},
{
el: "el-checkbox-group",
prop: "type",
label: "活动类型",
span: 10,
children: [
{
el: "el-checkbox",
label: "online",
children: "在线",
},
{
el: "el-checkbox",
label: "offline",
children: "离线",
},
],
rules: {
required: true,
message: "必填",
},
},
{
el: "el-radio-group",
label: "资源",
prop: "resources",
span: 10,
children: [
{
el: "el-radio",
label: "sponsor",
children: "赞助",
},
{
el: "el-radio",
label: "venue",
children: "场地",
},
],
rules: {
required: true,
message: "必填",
},
},
{
el: "el-upload",
label: "活动文件",
autoUpload: false,
prop: "files",
listType: "picture-card",
fileList: [
{
name: "food.jpeg",
url: "https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100",
},
],
children: [
{
el: "span", // 可以是 dom 标签
style: {
color: "var(--c-brand)",
},
children: "点击选择文件",
},
],
},
{
el: "el-input",
type: "textarea",
label: "活动描述",
prop: "desc",
rules: { required: true, message: "必填" },
},
{
el: "editor",
prop: "editor",
label: "活动计划",
modelValue:
'<p><span style="color: rgb(212, 56, 13); font-size: 29px;">这是富文本😄</span></p>',
},
])
const submit = ({ /* validate, */ rawFormModel }: any) => {
// validate 为校验方法,传入 autoValidateOnSubmit=false 会关闭组件的自动校验
console.log("校验通过:", rawFormModel)
}
const submitCheckFail = () => {
console.log("校验失败")
}
</script>
弹窗回显
v-model
存在即视为弹窗- 通过
ref
拿到组件的方法setFormModel
设置回显的字段
查看代码
vue
<template>
<div>
<KForm
ref="kFormRef"
v-model="show"
:options="options"
@submit="submit"
@submit-check-fail="submitCheckFail"
/>
<el-button @click="open">打开弹窗</el-button>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
import type { FormProps } from "@tomiaa/vue3-components"
import { KForm } from "@tomiaa/vue3-components"
const show = ref(false)
const kFormRef = ref()
// 活动标签列表,模拟异步数据
const selectTagData = ref<FormProps["options"]>([])
setTimeout(() => {
selectTagData.value = [
{
el: "el-option",
label: "标签一",
value: "one",
},
{
el: "el-option",
label: "标签二",
value: "two",
},
]
}, 5000)
// 表单配置,FormProps["options"] 声明以获取更好的 TS 类型提示
const options = ref<FormProps["options"]>([
{
el: "el-input",
label: "活动名称",
prop: "name",
modelValue: "这是双向绑定的值,也是默认值", // 存在 modelValue 时 prop 字段必填,否者值不会同步
},
{
el: "el-select",
label: "活动地点",
prop: "zone",
children: [
{
el: "el-option",
label: "上海",
value: "shanghai",
},
{
el: "el-option",
label: "北京",
value: "beijing",
},
],
rules: [
{
required: true,
message: "必填",
},
],
},
{
el: "el-select",
label: "活动标签",
prop: "tag",
children: selectTagData,
},
{
el: "el-date-picker",
prop: "startDate",
label: "开始时间",
span: 12,
},
{
el: "el-date-picker",
prop: "endDate",
label: "结束时间",
span: 12,
},
{
el: "el-switch",
prop: "instantDelivery",
label: "状态",
span: 4,
},
{
el: "el-checkbox-group",
prop: "type",
label: "活动类型",
span: 10,
children: [
{
el: "el-checkbox",
label: "online",
children: "在线",
},
{
el: "el-checkbox",
label: "offline",
children: "离线",
},
],
rules: {
required: true,
message: "必填",
},
},
{
el: "el-radio-group",
label: "资源",
prop: "resources",
span: 10,
children: [
{
el: "el-radio",
label: "sponsor",
children: "赞助",
},
{
el: "el-radio",
label: "venue",
children: "场地",
},
],
rules: {
required: true,
message: "必填",
},
},
{
el: "el-upload",
label: "活动文件",
autoUpload: false,
prop: "files",
listType: "picture-card",
children: [
{
el: "span", // 可以是 dom 标签
style: {
color: "var(--c-brand)",
},
children: "点击选择文件",
},
],
},
{
el: "el-input",
type: "textarea",
label: "活动描述",
prop: "desc",
rules: { required: true, message: "必填" },
},
{
el: "editor",
prop: "editor",
label: "活动计划",
},
])
// 模拟弹窗数据回显
const open = () => {
show.value = true
// data 是分页的数据
const data = {
id: "219087307",
test: "这是多余的字段",
name: "活动名",
zone: "beijing",
tag: "two",
startDate: Date.now(),
endDate: Date.now(),
instantDelivery: true,
type: ["offline"],
resources: "sponsor",
files: [
{
name: "food.jpeg",
url: "https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100",
},
],
desc: "活动描述",
editor:
'<p><span style="color: rgb(212, 56, 13); font-size: 29px;">这是富文本😄</span></p>',
}
// 设置表单数据回显
kFormRef.value.setFormModel(data, {
// includes: [], // 可以规定要回显哪些字段
exclude: ["test"], // 可以排除不需要的字段,这里 test 字段是多余的
})
}
const submit = ({ /* validate, */ rawFormModel }: any) => {
console.log("校验通过:", rawFormModel)
}
const submitCheckFail = () => {
console.log("校验失败")
}
</script>
插槽
查看代码
vue
<template>
<KForm
:options="options"
:show-actions="false"
>
<template #my-slot> 这是slot插槽 </template>
<template #inputFix>这是input插槽</template>
<template #my-file="scope">
这是文件的插槽,文件名:{{ scope.file.name }}
</template>
</KForm>
</template>
<script setup lang="ts">
import { ref } from "vue"
import type { FormProps } from "@tomiaa/vue3-components"
import { KForm } from "@tomiaa/vue3-components"
const options = ref<FormProps["options"]>([
{
slot: "my-slot",
},
{
el: "el-input",
label: "活动名称",
prop: "name",
children: {
slot: "inputFix", // 传给 KForm 的插槽
deepSlot: "prefix", // KForm 传给更深层的插槽名
},
},
{
el: "el-upload",
label: "活动文件",
autoUpload: false,
prop: "files",
listType: "picture-card",
fileList: [
{
name: "figure-2.png",
url: "/images/figure-2.png",
},
],
children: [
"点击选择文件", // 这里默认是 default 插槽
{
slot: "my-file", // 当前传递给 KForm 的插槽名
deepSlot: "file", // KFrom 传递给 el-upload 的插槽名
},
],
},
])
</script>
动态表单
查看代码
vue
<template>
<KForm
ref="dialogForm"
:model="formModel"
:gutter="15"
:options="options"
:actions-config="actionsConfig"
>
</KForm>
</template>
<script setup lang="ts">
import { computed, ref } from "vue"
import type { FormProps } from "@tomiaa/vue3-components/src"
import { KForm } from "@tomiaa/vue3-components"
const formModel = ref({ list: [] as string[] })
const inputList = computed<FormProps["options"]>(() =>
formModel.value.list.map((modelValue: string, i: number) => ({
el: "el-input",
modelValue,
prop: `list.${i}`,
label: `第${i + 1}行`,
rules: {
required: true,
message: `第${i + 1}行必填`,
},
}))
)
const actionsConfig: FormProps["actionsConfig"] = {
showCancel: false,
showReset: false,
submitText: "校验表单",
}
const options = ref<FormProps["options"]>([
{
el: "el-button",
type: "primary",
children: "新增",
span: 8,
onClick: () => {
formModel.value.list.push("")
},
},
{
el: "el-button",
type: "primary",
children: "设置第一行",
span: 8,
onClick: () => {
formModel.value.list[0] = "设置第一行的内容" + Date.now()
},
},
{
el: "el-button",
type: "danger",
children: "删除第一行",
span: 8,
onClick: () => {
formModel.value.list.shift()
},
},
// 二维数组会递归当做平级处理(外层会添加 el-col,el-form-item)
// 否则需要自己添加 { el: "el-form-item" },相应的属性也会失效
inputList,
{
el: "el-divider",
children: "分隔线",
},
])
</script>
复杂动态表单
查看代码
vue
<template>
<KForm
ref="dialogForm"
:model="formModel"
:gutter="15"
:options="options"
:actions-config="actionsConfig"
>
</KForm>
</template>
<script setup lang="ts">
import { computed, ref } from "vue"
import type { FormProps } from "@tomiaa/vue3-components/src"
import { KForm } from "@tomiaa/vue3-components"
const formModel = ref({ list: [] as any[] })
const inputList = computed<FormProps["options"]>(() =>
formModel.value.list.map((modelValue: string, i: number) => [
{
el: "el-input",
modelValue,
prop: `list.${i}.name`,
span: 8,
rules: {
required: true,
message: `第${i + 1}行姓名必填`,
},
},
{
el: "el-input",
modelValue,
prop: `list.${i}.age`,
span: 8,
rules: {
required: true,
message: `第${i + 1}行年龄必填`,
},
},
{
el: "el-button",
children: "删除",
type: "danger",
span: 8,
onClick() {
formModel.value.list.splice(i, 1)
},
},
])
)
const actionsConfig: FormProps["actionsConfig"] = {
showCancel: false,
showReset: false,
submitText: "校验表单",
}
const options = ref<FormProps["options"]>([
{
el: "span",
children: "姓名",
required: true,
span: 8,
},
{
el: "span",
children: "年龄",
required: true,
span: 8,
},
{
el: "el-button",
type: "primary",
children: "新增",
span: 8,
onClick: () => {
formModel.value.list.push({})
},
},
// 二维数组会递归当做平级处理(外层会添加 el-col,el-form-item)
// 否则需要自己添加 { el: "el-form-item" },相应的属性也会失效
inputList,
{
el: "el-divider",
children: "分隔线",
},
])
</script>
自定义控制栏
查看代码
vue
<template>
<KForm
:options="options"
:actions-config="actionsConfig"
>
</KForm>
</template>
<script setup lang="ts">
import { ref } from "vue"
import type { FormProps } from "@tomiaa/vue3-components/src"
import { KForm } from "@tomiaa/vue3-components"
const actionsConfig: FormProps["actionsConfig"] = {
showCancel: true, // 默认值
showSubmit: true, // 默认值
showReset: true, // 默认值
submitText: "提交", // 默认值
resetText: "重置", // 默认值
cancelText: "取消", // 默认值
custom(list) {
// 修改按钮列表
list[0].icon = "el-icon-menu"
// 以返回的列表渲染
return list
},
}
const options = ref<FormProps["options"]>([
{
el: "span",
children: "姓名",
required: true,
span: 8,
},
{
el: "el-divider",
children: "分隔线",
},
])
</script>
i18n 国际化
属性可以是 Ref 对象来动态显示
查看代码
ts
import { computed } from "vue"
import { useI18n } from "vue-i18n"
const { t } = useI18n()
const queryAttrs = ref([
{
el: "el-input",
label: computed(() => t("名称")),
prop: "name",
placeholder: "请输入",
clearable: true,
},
{
el: "el-input",
label: computed(() => t("代码")),
prop: "code",
placeholder: "请输入",
clearable: true,
},
{
el: "el-input",
label: computed(() => t("域名")),
prop: "host",
placeholder: "请输入",
clearable: true,
},
])
也可以直接是字符串以$t(
或t(
开头与)
结尾即视为i18n
,内部会调用$t
获取语言配置
按需引入
vue
<script setup lang="ts">
import { KForm } from "@tomiaa/vue3-components"
</script>
属性
属性 | 说明 | 类型 | 默认值 | 必填 |
---|---|---|---|---|
modelValue | 在弹窗中显示,modelValue 存在也会视为弹窗 | boolean | undefined | |
showActions | 显示操作栏,为 true 时且弹窗时存在 footer 插槽时不会生效 | boolean | true | |
actionsConfig | 操作栏配置 | [ActionsConfig](#ActionsConfig 操作栏配置) | ||
autoValidateOnSubmit | submit 时自动校验,校验通过后触发 @submit 事件 | boolean | true | |
options | 表单配置 | FormOptions[] | ||
...rest | 剩余属性为el-form 的属性与el-dialog 的属性(modelValue 存在时) |
ActionsConfig 操作栏配置
属性 | 说明 | 类型 | 默认值 | 必填 |
---|---|---|---|---|
showCancel | 是否显示取消按钮 | boolean | true | |
cancelText | 取消按钮文字 | string | 取消 | |
showReset | 是否显示重置按钮 | boolean | true | |
resetText | 重置按钮文字 | string | 重置 | |
showSubmit | 是否显示提交按钮 | boolean | true | |
submitText | 提交按钮文字 | string | 提交 | |
custom | 自定义控制栏方法,参数为控制按钮列表数组,需要返回该数组 | CustomElementProps["list"] | ... | |
... | ElCol 的属性 |
FormOptions 配置
属性 | 说明 | 类型 | 默认值 | 必填 |
---|---|---|---|---|
el | 标签名/组件(存在 render 或 setup 方法视为组件) | element-plus 组件名 | dom 标签名 | 'editor' | string | ||
ref | 该属性赋值 ref 对象可以同步拿到当前 el 的 vue ref 对象,如果该字段是函数,则会传入当前的 ref 对象 | Ref<any> | (ref: Ref<any>) => void | 当前 el 的 ref 对象 | |
editorAttrs | wangEditor富文本的编辑器配置,el="editor"时生效 | Object | ||
toolbarAttrs | wangEditor富文本的工具栏配置,el="editor"时生效 | Object | ||
slot | 插槽名称(存在则视为插槽) | string | ||
deepSlot | 将slot 传递给深层次的插槽名称 | string | ||
children | 子元素 | FormOptions | FormOptions[] | DefineComponent | DefineComponent[] | Ref<any> | string | ||
...rest | 剩余属性包括element-plus 所有组件的属性与事件 |
注意
默认情况下el-form-item
会被el-col
包裹一层,FormOptions
直接填el-col
的属性可以进行表达布局,但在组件传入属性:inline="true"
时外层不会包裹el-col
,因为inline
属性开启了el-form
的行内表单。
事件
事件名 | 说明 | 回调参数 |
---|---|---|
submit | 提交按钮 | { formRef,// el-form 的 ref dialogRef, // el-dialog 的 ref formModel, // 表单的数据(双向绑定的) validate, // el-form 的表单校验方法 rawFormModel, // 接触绑定表单数据 } |
reset | 重置按钮 | 与submit 一致 |
cancel | 取消按钮,取消时会默认发送事件emit("update:modelValue", false) | |
submitCheckFail | autoValidateOnSubmit 为 true 时,submit 校验 form 失败 | |
update:model | 同步 model,model 改变时 | |
...rest | 剩余事件为el-form 事件与el-dialog 事件(modelValue 属性存在时) |