Element UI el-table form 表单的封装思路
思路一: 将所有 form 表单类型都在 el-column-item 组件中定义好,然后根据传入的属性控制展示哪一个 form 表单类型
部分代码如下:
<template>
<div>
<el-row style="padding: 0 20px">
<el-col :span="24" style="text-align: right">
<el-button @click.native="addRow" v-if="!isOperated"
><i class="el-icon-plus el-icon--left"></i>新增行</el-button
>
</el-col>
</el-row>
<el-row style="padding: 20px">
<el-table
ref="multipleTable"
stripe
border
height="250"
:data="data"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column
type="index"
label="序号"
width="50"
align="center"
fixed="left"
>
</el-table-column>
<template v-for="(v, i) in modulsList">
<el-table-column
v-if="!v.hidden"
:label="v.label"
:prop="v.prop"
:key="i"
:width="v.width"
align="center"
>
<template slot-scope="scope">
<el-form-item
:prop="
dataTag ? `${dataTag}.${scope.$index}.${v.prop}` : v.prop
"
label-width="15px"
label=" "
:rules="v.rules"
>
<template v-if="v.type === 'text'">
<el-input
type="text"
v-model="scope.row[v.prop]"
:disabled="v.disabled"
></el-input>
</template>
<template v-else-if="v.type === 'number'">
<el-input-number
v-model="scope.row[v.prop]"
:min="0"
></el-input-number>
</template>
<template v-else-if="v.type === 'textarea'">
<el-input
type="textarea"
:maxlength="v.maxlength"
:show-word-limit="v.limit"
v-model="scope.row[v.prop]"
:disabled="v.disabled"
></el-input>
</template>
<template v-else-if="v.type === 'datePicker'">
<el-date-picker
v-model="scope.row[v.prop]"
type="date"
placeholder="选择日期"
value-format="timestamp"
:disabled="v.disabled"
>
</el-date-picker>
</template>
<template v-else-if="v.type === 'select'">
<el-select v-model="scope.row[v.prop]" placeholder="请选择">
<template v-for="(x, j) in v.options">
<el-option
:label="x.label"
:value="x.value"
:key="j"
></el-option>
</template>
</el-select>
</template>
<template v-else-if="v.type === 'switch'">
<el-switch v-model="scope.row[v.prop]"></el-switch>
</template>
<template v-else-if="v.type === 'selectRemote'">
<el-select
v-model="scope.row[v.prop]"
filterable
remote
placeholder="请输入"
:remote-method="v.searchMethod"
@change="v.changeMethod"
>
<el-option
v-for="(item, i) in v.selectOption"
:key="i"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</template>
<template v-else> </template>
</el-form-item>
</template>
</el-table-column>
</template>
<el-table-column
label="操作"
width="100"
align="center"
fixed="right"
v-if="!isOperated"
>
<template slot-scope="scope">
<el-button type="text" size="mini" @click="deleteRow(scope.$index)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-row>
</div>
</template>
<script>
export default {
components: {},
props: {
// 展示模块
// #description label:名称、prop:Data的对应字段、,type:类型 , default: 新增行默认值
modulsList: {
type: Array,
default: () => {}
},
// 渲染数据
data: {
type: Array,
default: () => []
},
// 校验标签头
dataTag: {
type: String,
default: ''
},
isOperated: Boolean
},
data() {
return {}
},
methods: {
// 新增行
addRow() {
let addIndex = this.data.length
let newArr = {}
this.modulsList.forEach((v) => {
newArr[v.prop] = v.default
})
this.$set(this.data, addIndex, newArr)
console.log('新增行', this.data)
},
// 删除行
deleteRow(index) {
if (this.data.length <= 1) {
this.$message.error('至少含有一条')
return false
}
this.data.splice(index, 1)
console.log('删除行', this.data)
}
},
mounted() {
// 至少含有一条
if (this.data.length === 0) {
this.addRow()
}
}
}
</script>
<style lang="scss" scoped>
.el-table > .el-input,
.el-textarea,
.el-select,
.el-date-editor,
.el-input-number {
width: 100%;
}
</style>
思路二: 将所有 form 表单都单独封装,然后通过一个 js 文件 defineAsyncComponent
汇总这些单独封装的表单组件.使用的时候,通过 component is
来引入使用.
效果如下:
部分代码如下
汇总表单组件的 js文件代码:
import { defineAsyncComponent } from 'vue'
const formMap = {
FInput: defineAsyncComponent(() =>
import('@/components/form/items/fInput.vue')
),
FRadio: defineAsyncComponent(() =>
import('@/components/form/items/fRadio.vue')
),
FSwitch: defineAsyncComponent(() =>
import('@/components/form/items/fSwitch.vue')
),
FSelect: defineAsyncComponent(() =>
import('@/components/form/items/fSelect.vue')
),
FCheckbox: defineAsyncComponent(() =>
import('@/components/form/items/fCheckbox.vue')
),
FDateTimePicker: defineAsyncComponent(() =>
import('@/components/form/items/fDateTimePicker.vue')
),
FSelectUser: defineAsyncComponent(() =>
import('@/components/form/items/fSelectUser.vue')
),
FPartNo: defineAsyncComponent(() =>
import('@/components/form/items/fPartNo.vue')
),
FSelectSupplier: defineAsyncComponent(() =>
import('@/components/form/items/fSelectSupplier.vue')
),
FSupplierMaster: defineAsyncComponent(() =>
import('@/components/form/items/fSupplierMaster.vue')
),
FCascader: defineAsyncComponent(() =>
import('@/components/form/items/fCascader.vue')
)
}
export default formMap
封装的 formTable 组件代码如下:
<template>
<div class="formTable">
<el-table :data="formTableList.tableData" border style="width: 100%">
<el-table-column
v-for="(item, index) in formTableList.tableHeader"
:key="index"
:prop="item.prop"
:label="item.label"
align="center"
>
<template slot-scope="scope">
<span v-if="item.isTitle"> {{ scope.row[item.prop] }}</span>
<el-form
v-if="!item.isTitle"
ref="refForm"
:model="scope.row"
:rules="formTableList.formRules"
:label-width="labelWidth"
class="demo-form-inline"
>
<el-form-item :prop="item.prop" label=" ">
<component
:is="formMap[item.formType]"
:meta="item.meta"
:obj="scope.row"
></component>
</el-form-item>
</el-form>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import formMap from '@/components/form/formMap.js'
export default {
name: 'FormTable',
// watch: {
// formTableList: {
// deep: true,
// handler(val) {
// console.log(val)
// }
// }
// },
props: {
formTableList: {
type: Object,
default() {
return {}
}
},
labelWidth: {
type: String,
default: 'auto'
}
},
data() {
return {
formMap
}
},
methods: {
modelRef() {
return this.$refs.refForm
}
}
}
</script>
<style lang="scss" scoped>
.formTable {
padding-bottom: 20px;
}
::v-deep .el-select {
width: 100%;
}
</style>
使用 formTable 组件配置项代码如下:
<FormTable
ref="partFourModelRef"
:formTableList="formTableList"
></FormTable>
formTableList: {
formRules: {
RPN: [{ required: true, message: '请输入', trigger: ['blur'] }],
yanzhongdu: [
{ required: true, message: '请输入', trigger: ['blur'] }
],
pindu: [{ required: true, message: '请输入', trigger: ['blur'] }],
tancedu: [{ required: true, message: '请输入', trigger: ['blur'] }]
},
tableHeader: [
{
prop: 'fangmian',
label: '方面',
isTitle: true,
meta: {
fProp: 'fangmian'
}
},
{
prop: 'RPN',
label: 'RPN',
formType: 'FInput',
meta: {
fProp: 'RPN'
}
},
{
prop: 'yanzhongdu',
label: '严重度(S)',
formType: 'FInput',
meta: {
fProp: 'yanzhongdu'
}
},
{
prop: 'pindu',
label: '频度(O)',
formType: 'FInput',
meta: {
fProp: 'pindu'
}
},
{
prop: 'tancedu',
label: '探测度(D)',
formType: 'FInput',
meta: {
fProp: 'tancedu'
}
}
],
tableData: [
{
fangmian: '改善前'
},
{
fangmian: '改善后'
}
]
}