文章目录
- 前言
- 一、新增table组件
- 二、使用步骤
前言
在 基于element-plus定义表单配置化 基础上,封装个Element-plus的table表格
由于表格不同于form组件,需自定义校验器,以下组件配置了单个校验,及提交统一校验方法,且自定义必填校验*
显示和校验错误部分边框标红等,实际可根据业务及不同场景优化改造相关定义
后期抽空新增表格行及删除行等功能,
一、新增table组件
- table-configuration/index.vue
<template><el-tableborderref="tableRef":show-header="showHeader":data="tableData"style="width: 100%"tooltip-effect:max-height="tablemaxHeight"><el-table-column type="selection" :fixed="selectionFixed" width="55" v-if="hasSelection"/><template v-for="(item, index) in tableProperty" :key="item"><el-table-column:align="align":sortable="item.sortable":min-width="item.width":show-overflow-tooltip="showOverflowTooltip":label="item.label"><template #header><div :class="[getTableHeader(item.property.rules)]" v-html="item.label"></div></template><template #default="scope"><component :class="[scope.$index >=0 && getIsErrorClass(scope.$index, index)]"v-model:content="scope.row[item.field]"v-model="scope.row[item.field]":property="{...item.property, name: item.field}":is="item.type"@fieldBlur="(val) => blur(val, item, scope.$index, index)"@fieldChange="(val) => change(val, item, scope.$index, index)" /></template></el-table-column></template></el-table>
</template>
<script lang="ts" src="./index.ts"/>
<style lang="less">
.is-error .el-select-v2__wrapper,.is-error .el-select-v2__wrapper:focus,.is-error .el-textarea__inner,.is-error .el-textarea__inner:focus {box-shadow: 0 0 0 1px var(--el-color-danger) inset
}.is-error .el-input__wrapper {box-shadow: 0 0 0 1px var(--el-color-danger) inset
}
.table {&_header:before {content: "*";color: var(--el-color-danger);margin-right: 4px;}
}
</style>
- table-configuration/index.ts
import { tableHooks } from "@/composables/table-hooks";
import { computed, defineComponent, reactive, ref } from "vue";
import Input from "@/components/form-configuration/input.vue";
import Select from "@/components/form-configuration/select.vue";
import Vhtml from "@/components/form-configuration/v-html.vue";
import Upload from "@/components/form-configuration/upload.vue";
import Switch from "@/components/form-configuration/switch.vue";
import Radio from "@/components/form-configuration/radio.vue";
import Checkbox from "@/components/form-configuration/checkbox.vue";
import Date from "@/components/form-configuration/date.vue";
import Cascader from "@/components/form-configuration/cascader.vue";
import { isArray } from "lodash-es";
import { ElMessage } from "element-plus";
import type { rulesType } from "@/interface";const ruleType = {required: false,message: '',trigger: '',validator: (val: any) =>{return val}
}
const fieldProperty = {label: 'demo',type: 'Input',field: 'demo',width: '120px',err: '',property: {maxlength: 200,rules: [ruleType]}
}
export default defineComponent({components: {Input,Select,Vhtml,Upload,Switch,Radio,Checkbox,Date,Cascader,},props: {align: {type: String,default: 'left', // left / center / right},showHeader: {type: Boolean,default: true,},selectionFixed: {type: Boolean,default: false,},showOverflowTooltip: {type: Boolean,default: true,},hasSelection: {type: Boolean,default: false,},property: {type: Object,default() {return [ fieldProperty ];},},data: {type: Object,default() {return {};},},},setup(props, { emit }) {const { tablemaxHeight } = tableHooks();const tableRef = ref()const tableData = computed({get() {return props.data;},set(val) {emit("update:data", val);},});const noType = 'noType'const tableProperty = computed(() => props.property);const blur = (val: any, item: typeof fieldProperty, rowIndex: number, colIndex: number) => {let arr: Array<boolean> = []if (item.property.rules && isArray(item.property.rules)) {arr = validateForField(item, val, 'blur', rowIndex, colIndex)}if (!arr.length) {emit('blur', {val, field: item.field, rowIndex, colIndex}) // 触发clearIsError(rowIndex, colIndex)}}const change = (val: any, item: typeof fieldProperty, rowIndex: number, colIndex: number) => {let arr: Array<boolean> = []if (item.property.rules && isArray(item.property.rules)) {arr = validateForField(item, val, 'change', rowIndex, colIndex)}if (!arr.length) {emit('change', {val, field: item.field, rowIndex, colIndex}) // 触发clearIsError(rowIndex, colIndex)}}const isError = ref<{rowIndex: number, colIndex: number}[]>([])const validateForField = (item: typeof fieldProperty, val: any, type: string, rowIndex: number, colIndex: number) => {let arr: Array<boolean> = []item.property.rules.forEach((valid) => {const types = [valid.trigger, noType]if (valid.required && !val) {ElMessage.error(valid.message)arr.push(false)isError.value.push({rowIndex, colIndex,})return}if (!valid.required && !val || !types.includes(type)) returnif (!valid.validator) returnconst bool = valid.validator(val)if (!bool) {ElMessage.error(valid.message)arr.push(bool)isError.value.push({rowIndex, colIndex,})}})return arr}const clearIsError = (rowIndex: number, colIndex: number) => {if (rowIndex === -1) {isError.value = []} else {isError.value = isError.value.filter((item) => {return !((item.rowIndex === rowIndex) && (item.colIndex === colIndex))})}}const validate = () => {let arr: Array<boolean> = []clearIsError(-1, -1)tableData.value.forEach((data: object, rowIndex: number) => {tableProperty.value.forEach((tabPro: any, colIndex: number) => {if (!tabPro.property.rules) returnconst field = tabPro.field as keyof typeof dataarr.push(...validateForField(tabPro, data[field], noType, rowIndex, colIndex))});});return !arr.length}const getIsErrorClass = computed(() => {return (rowIndex: number, colIndex: number) => {let bool = falseisError.value.forEach((error) => {(error.rowIndex === rowIndex) && (error.colIndex === colIndex) && (bool = true)})return bool ? 'is-error' : ''}})const getTableHeader = (rules: rulesType[]) => {if (!rules) return ''return !!rules.filter((item) => item.required).length ? 'table_header' : ''}return {tableRef,tablemaxHeight,tableProperty,tableData,isError,getIsErrorClass,getTableHeader,change,blur,validate};},
});
二、使用步骤
<TableConfigurationref="supplierListRef"v-model:data="supplierListEntity.product":hasSelection="true":selectionFixed="true":property="tableProperty"align="center"/>
import { defineComponent, reactive, ref } from 'vue'
import TableConfiguration from '@/components/table-configuration/index.vue'
export default defineComponent({components: {TableConfiguration},setup() {const tableRef = ref()const tableProperty = reactive([{ label: 'Input01', type: 'Input', field: 'Input01', property: {maxlength: 500,rules: [{ required: false, message: 'error', trigger: 'blur', validator: (value: string) => {return /^\+?[1-9][0-9]*$/.test(value)}}]}},{ label: 'Input02', type: 'Input', field: 'Input02', width: '200px', property: {maxlength: 500,rules: [{ required: true, message: 'error', trigger: 'blur' }]}}])const tableEntity = reactive({table: [{Input01: '',Input02: '',}]})const validate = () => {tableRef.value.validate()}return {tableRef,tableProperty,tableEntity,validate}},
})