动态表单的场景还是比较多的,其中两个用途比较常见第一个是方便多处form表单复用,第二个就是动态表单,点击按钮新增一个input或者select框,代码在下面
form组件封装
<template>
<!-- <el-form v-bind="$attrs" :model="model" ref="formRef"> -->
<el-form v-bind="$attrs" :model="model" ref="formRef">
<el-row>
<el-col v-for="item in schema" :key="item.key" :span="item.span">
<el-form-item :label="item.label" :prop="item.model">
<template v-if="item.component === 'input'">
<el-input
v-model="model[item.model]"
v-bind="item.props"
></el-input>
</template>
<template v-else-if="item.component === 'select'">
<el-select v-model="model[item.model]" v-bind="item.props">
<el-option
v-for="option in item.selectOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</template>
<template v-else-if="item.component === 'submit-button'">
<el-button v-bind="item.props" @click="submit(item.handleSubmit)">{{
item.btnText
}}</el-button>
</template>
<template v-else-if="item.component === 'button'">
<el-button v-bind="item.props || {}" v-on="item.listeners || {}">{{
item.btnText
}}</el-button>
</template>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script lang="ts">
export default {
name: "XForm",
};
</script>
<script lang="ts" setup>
import type { FormInstance } from "element-plus";
import { ref } from "vue";
defineProps<{
schema: any[];
model: any;
}>();
const formRef = ref<FormInstance>();
const submit = async (callback: () => {}) => {
// 进行表单校验
await formRef.value?.validate();
// 如果通过了, 调用传入的回调来通知父组件
callback();
};
</script>
<style scoped></style>
组件使用
<template>
<h2>表单封装测试</h2>
<FormTest />
<hr />
<button @click="add">添加一项</button>
<XForm :schema="schema" :model="model" :rules="rules" label-width="100px" />
</template>
<script lang="ts">
export default {
name: "Test1",
};
</script>
<script lang="ts" setup>
import { reactive, ref } from "vue";
import XForm from "../components/XForm/index.vue";
import FormTest from "./FormTest.vue";
/*
key: 唯一标识
span: 栅格数
component: 组件名, 对应不同的element表单项
input ==> el-input
select ==> el-select
cancel-button ==> 取消el-button
submit-button ==> 提交el-button
label: 左侧标题
model: 收集输入数据的属性名
props: 直接传递给表单项的属性
selectOptions: 用于显示表单项列表的数组
btnText: 按钮文本
handleSubmit: 点击提交按钮的回调
listeners: 包含事件监听的对象
*/
const schema = ref([
{
key: "username",
span: 12,
component: "input", // el-input
label: "用户名",
model: "username",
props: {
placeholder: "请输入用户名",
},
},
{
key: "pwd",
span: 12,
component: "input",
label: "密码",
model: "password",
props: {
placeholder: "请输入密码",
type: "password",
},
},
{
key: "city",
component: "select",
label: "选择城市",
span: 8,
model: "city",
props: {
placeholder: "请选择城市",
},
selectOptions: [
{
label: "武汉",
value: "wh",
},
{
label: "北京",
value: "bj",
},
{
label: "深圳",
value: "sz",
},
],
},
{
key: "desc",
component: "input",
label: "描述",
model: "description",
props: {
type: "textarea",
rows: 2,
placeholder: "请输入描述",
},
},
{
key: "submit-btn",
component: "submit-button",
span: 2,
props: {
type: "primary",
},
btnText: "提交",
handleSubmit: () => {
alert("校验通过后发请求" + JSON.stringify(model));
},
},
{
key: "cancel-button",
component: "button",
span: 2,
btnText: "返回2",
listeners: {
click: () => alert("返回上一个页面"),
// xxx: () => {}
},
},
]);
const model = reactive({
username: "",
password: "",
city: "",
description: "",
});
const rules = {
// 表单校验名称必须和数据名称一致
username: [{ required: true, message: "用户名是必须的", trigger: "blur" }],
password: [{ required: true, message: "密码是必须的", trigger: "blur" }],
};
const add = () => {
schema.value.push({
key: "pwd1",
span: 12,
component: "input",
label: "密码",
model: "password",
props: {
placeholder: "请输入密码",
type: "password",
},
});
};
// 封装一个
function getList() {
return new Promise((res) => {
res([{ name: "中岛瑞" }]);
});
}
function test111(cb) {
getList().then((res) => {
cb(res);
});
}
test111((aaa) => {
console.log(aaa);
});
</script>
<style scoped></style>