该项目git地址
- 结合项目源码更容易看懂 代码更完整
随便扯扯
-
以前做项目的过程中呢 发现封装组件能够提高开发效率并且降低耦合度
-
也在这里踩了很多坑 由刚开始的只能父子组件传值 到抽离出一个比较通用的公共组件
- 也极大的提高了开发效率
-
这里也是学习到了一种极具通用性的组件开发方式 也在此做一个记录 进行分享
-
也算是对之前的学习内容进行一个总结和巩固吧
element 配置式 组建的封装
-
之前在做一个项目的时候 有一个需求 使用 element 需要获取一个输入的信息 但是这个这种获取输入页面有很多相似的 于是就开始捣鼓怎么把他抽离成一个公共组件 在一直优化的过程中了解到了这种配置式的封装 yysy 真滴好用
-
话不多说 先看效果
-
-
思路
-
因为使用的是 element
- 1.使用 其中的布局 Layout 可以实现传参控制布局 与配置式十分契合
- 2.其中的 各个组件的宽度也有参数可以进行配置
- 3.其中各种 表单组件可以通过 type 传递参数控制 那么就可以配置不同的 表单组件
- 4.使用一个 for 循环将配置的参数直接传递进去就行了
-
代码 里面有注释
-
-
里面使用了 ts 进行类型限制 这个关系不大
-
组件代码
-
<template> <div class="hy-form"> <div class="header"> <slot name="header"></slot> </div> <!-- 使用 from 表单收集信息 --> <el-form :label-width="props.labelWidth"> <el-row> <!-- 遍历配置信息 --> <template v-for="item in props.formItems" :key="item.label"> <el-col v-bind="colLayout"> <el-form-item :label="item.label" :rules="item.rules" :style="props.itemStyle" > <!-- 输入框 --> <template v-if="item.type === 'input' || item.type === 'password'" > <el-input v-bind="item.otherOptions" v-model="formData[`${item.field}`]" :placeholder="item.placeholder" :show-password="item.type === 'password'" /> </template> <!-- 选择框 --> <template v-else-if="item.type === 'select'"> <el-select v-bind="item.otherOptions" v-model="formData[`${item.field}`]" :placeholder="item.placeholder" style="width: 100%" > <el-option v-for="option in item.options" :key="option.value" :value="option.value" >{{ option.title }}</el-option > </el-select> </template> <!-- 日期框 --> <template v-else-if="item.type === 'datepicker'"> <el-date-picker v-bind="item.otherOptions" v-model="formData[`${item.field}`]" style="width: 100%" ></el-date-picker> </template> </el-form-item> </el-col> </template> </el-row> </el-form> <div class="footer"> <slot name="footer"></slot> </div> </div> </template> <script setup lang="ts"> import { defineProps, defineEmits, PropType, ref, watch } from 'vue' import { IFormItem } from '../types' // 传递过来配置的参数就行 const props = defineProps({ modelValue: { type: Object, required: true, }, formItems: { type: Array as PropType<IFormItem[]>, // 传值的时候 如果是数组或者对象 一定要使用箭头函数来做默认值 // 就是要用一个函数使用 return 返回 箭头函数时简写 但是因为 this 的原因 箭头函数会更好用 default: () => [], }, // 设置输入框左边字体的宽度 labelWidth: { type: String, default: '100px', }, itemStyle: { type: Object, default: () => ({ padding: '10px 40px' }), }, // 响应式的布局参数 // span 的话 默认 24 份 设置为 8 就是一行分三份 colLayout: { type: Object, default: () => ({ xl: 6, // >1920px 4个 lg: 8, md: 12, sm: 24, xs: 24, }), }, }) const emit = defineEmits(['update:modelValue']) const formData = ref({ ...props.modelValue }) watch( formData, (newValue) => { console.log(newValue) emit('update:modelValue', newValue) }, { deep: true, } ) </script> <style scoped lang="less"> .hy-form { padding-top: 22px; } </style> - 父子组件传参的下一篇讲 这里踩了挺多坑的 主要是获取子组件 输入框中的值 父子组件是双向绑定的 说多了都是泪啊
-
-
父组件的配置
-
export const searchFormConfig: IForm = { labelWidth: '100px', itemLayout: { padding: '10px 10px', }, colLayout: { span: 8, }, formItems: [ { field: 'id', type: 'input', label: 'id', placeholder: '请输入id', }, { field: 'name', type: 'input', label: '用户名', placeholder: '请输入用户名', }, { field: 'password', type: 'password', label: '密码', placeholder: '请输入密码', }, { field: 'sport', type: 'select', label: '喜欢的运动', placeholder: '请选择喜欢的运动', options: [ { title: '篮球', value: 'basketball' }, { title: '足球', value: 'football' }, ], }, { field: 'createTime', type: 'datepicker', label: '创建时间', otherOptions: { startPlaceholder: '开始时间', endPlaceholder: '结束时间', type: 'daterange', }, }, ], }
-
- 先这样吧 以后看看补充详细点