1 场景
一般表单我们直接默认布局,也就是单列布局,突然有个人员信息表单,需要双列布局的需求,简单实现并拓展下
2 思路
直接无脑div+flex布局实现
3 代码
<template><el-form ref="formRef" :model="formData" label-width="80px"><div class="form-top"><div class="form-top--left"><el-form-item label="姓名" prop="name"><el-input v-model="formData.name" placeholder="请输入姓名" /></el-form-item><el-form-item label="年龄" prop="age"><el-input v-model="formData.age" placeholder="请输入年龄" /></el-form-item><el-form-item label="性别" prop="sex"><el-radio-group v-model="formData.sex"><el-radio :label="1">男</el-radio><el-radio :label="2">女</el-radio></el-radio-group></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="formData.email" placeholder="请输入邮箱" /></el-form-item><el-form-item label="排序" prop="sort" placeholder="请输入排序号"><el-input-number v-model="formData.sort" :min="1" /></el-form-item></div><div class="form-top--right"><el-form-item label="备注" prop="remark"><el-inputv-model="formData.remark"type="textarea"placeholder="请输入备注"maxlength="100"show-word-limitresize="none"/></el-form-item><el-form-item label="说明" prop="config"><el-inputv-model="formData.config"placeholder="请输入说明"type="textarea"show-word-limitmaxlength="200":autosize="{ minRows: 6, maxRows: 6 }"/></el-form-item></div></div><div class="form-bottom"><el-form-item><el-button type="primary" @click="handleSubmit">确 定</el-button><el-button type="warning" @click="handleClose">取 消</el-button></el-form-item></div></el-form>
</template><script setup lang="ts">
const formRef = ref();const formData = reactive({remark: "",age: 10,config: "",email: "",sex: "",id: null,name: "",sort: 0,
});const handleClose = () => {};
const handleSubmit = () => {};
</script>
<style lang="scss" scoped>
.container {width: 600px;margin-top: 100px;.form-top {display: flex;justify-content: space-between;.form-top--right {flex: 1;}}.form-bottom {display: flex;justify-content: flex-end;}
}
</style>
这样的无脑实现实在是对不起付出的时间,不嫩复用是最大问题
4 拓展
封装el-form,增加slot
// Form.vue
<template><el-form><slot></slot><div class="form-top" v-if="!slot.default"><div class="form-top--left" v-if="slot.left"><slot name="left"></slot></div><div class="form-top--right" v-if="slot.right"><slot name="right"></slot></div></div><div class="form-bottom" v-if="slot.bottom"><slot name="bottom"></slot></div></el-form>
</template><script setup lang="ts">
const slot = useSlots();
</script>
<style lang="scss" scoped>
.form-top {display: flex;justify-content: space-between;.form-top--left {flex: 1;}.form-top--right {flex: 1;}
}
.form-bottom {display: flex;justify-content: flex-end;
}
</style>
// index.vue
<template><Form ref="formRef" :model="formData" label-width="80px"><template #left><el-form-item label="姓名" prop="name"><el-input v-model="formData.name" placeholder="请输入姓名" /></el-form-item><el-form-item label="年龄" prop="age"><el-input v-model="formData.age" placeholder="请输入年龄" /></el-form-item><el-form-item label="性别" prop="sex"><el-radio-group v-model="formData.sex"><el-radio :label="1">男</el-radio><el-radio :label="2">女</el-radio></el-radio-group></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="formData.email" placeholder="请输入邮箱" /></el-form-item><el-form-item label="排序" prop="sort" placeholder="请输入排序号"><el-input-number v-model="formData.sort" :min="1" /></el-form-item></template><template #right><el-form-item label="备注" prop="remark"><el-inputv-model="formData.remark"type="textarea"placeholder="请输入备注"maxlength="100"show-word-limitresize="none"/></el-form-item><el-form-item label="说明" prop="config"><el-inputv-model="formData.config"placeholder="请输入说明"type="textarea"show-word-limitmaxlength="200":autosize="{ minRows: 6, maxRows: 6 }"/></el-form-item></template><template #bottom><el-form-item><el-button type="primary" @click="handleSubmit">确 定</el-button><el-button type="warning" @click="handleClose">取 消</el-button></el-form-item></template></Form>
</template><script setup lang="ts">
import Form from "./Form.vue";
const formRef = ref();//添加人员表单
const formData = reactive({remark: "",age: 10,config: "",email: "",sex: "",id: null,name: "",sort: 0,
});const handleClose = () => {};
const handleSubmit = () => {};
</script>
<style lang="scss" scoped>
.form-top {display: flex;justify-content: space-between;.form-top--right {flex: 1;}
}
.form-bottom {display: flex;justify-content: flex-end;
}
</style>
依然不够通用,因为布局是固定的,如果想要其他布局,要么修改Form.vue,要么重新封装
5 继续拓展
抽出layout,形成Layout.vue组件,拿出祖传技艺slot传递
// Layout.vue
<template><div><slot></slot><div class="form-top" v-if="!slot.default"><div class="form-top--left" v-if="slot.left"><slot name="left"></slot></div><div class="form-top--right" v-if="slot.right"><slot name="right"></slot></div></div><div class="form-bottom" v-if="slot.bottom"><slot name="bottom"></slot></div></div>
</template><script setup lang="ts">
const slot = useSlots();
</script>
<style lang="scss" scoped>
.form-top {display: flex;justify-content: space-between;.form-top--left {flex: 1;}.form-top--right {flex: 1;}
}
.form-bottom {display: flex;justify-content: flex-end;
}
</style>
// Form.vue
<template><el-form><Layout><template v-for="item in Object.keys(slot)" :key="item" #[item]><slot :name="item"></slot></template></Layout></el-form>
</template><script setup lang="ts">
import Layout from "./Layout.vue";
const slot = useSlots();
</script>
<style lang="scss" scoped></style>
// index.vue
<template><Form ref="formRef" :model="formData" label-width="80px"><template #left><el-form-item label="姓名" prop="name"><el-input v-model="formData.name" placeholder="请输入姓名" /></el-form-item><el-form-item label="年龄" prop="age"><el-input v-model="formData.age" placeholder="请输入年龄" /></el-form-item><el-form-item label="性别" prop="sex"><el-radio-group v-model="formData.sex"><el-radio :label="1">男</el-radio><el-radio :label="2">女</el-radio></el-radio-group></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="formData.email" placeholder="请输入邮箱" /></el-form-item><el-form-item label="排序" prop="sort" placeholder="请输入排序号"><el-input-number v-model="formData.sort" :min="1" /></el-form-item></template><template #right><el-form-item label="备注" prop="remark"><el-inputv-model="formData.remark"type="textarea"placeholder="请输入备注"maxlength="100"show-word-limitresize="none"/></el-form-item><el-form-item label="说明" prop="config"><el-inputv-model="formData.config"placeholder="请输入说明"type="textarea"show-word-limitmaxlength="200":autosize="{ minRows: 6, maxRows: 6 }"/></el-form-item></template><template #bottom><el-form-item><el-button type="primary" @click="handleSubmit">确 定</el-button><el-button type="warning" @click="handleClose">取 消</el-button></el-form-item></template></Form>
</template><script setup lang="ts">
import Form from "./Form.vue";
const formRef = ref();//添加人员表单
const formData = reactive({remark: "",age: 10,config: "",email: "",sex: "",id: null,name: "",sort: 0,
});const handleClose = () => {};
const handleSubmit = () => {};
</script>
<style lang="scss" scoped>
.form-top {display: flex;justify-content: space-between;.form-top--right {flex: 1;}
}
.form-bottom {display: flex;justify-content: flex-end;
}
</style>
6 总结
-
布局和数据分离
-
灵活扩展layout
2.1 可以建立多个layout文件,批量引入(或动态引入)Form.vue中 ,Form.vue中利用动态组件component加载各个layout文件
2.2 可以建立多个layout文件,批量引入(或动态引入)LayoutIndex.vue文件中,LayoutIndex.vue文件利用动态组件component加载各个layout文件,然后Form.vue中只渲染LayoutIndex,同时通过传参决定渲染那个layout
-
新增layout时,只需要新增文件(所有layout文件已经被批量引入<或动态引入>),符合“开闭”原则
tip:
批量引入(vite):import.meta.glob(‘./layout/**/*.vue’);
动态引入:defineAsyncComponent(() => import(
./components/${layoutName}.vue
));