Element plus中 表格 使用 表单动态校验

Element plus中表格使用表单校验

1、table组件,html部分

<template>
    <div class="set-f">
        <el-form :model="fromData" ref="tableFrom">
        <el-table ref="tableRef" class="minheight"  v-loading="loading" :data="fromData.list" :stripe="_option.stripe" :height="_option.height"
            :maxHeight="_option.maxHeight" :size="_option.size" :showHeader="_option.showHeader" scrollbar-always-on
            :tooltipEffect="_option.tooltipEffect" :row-style="_option.rowStyle" :row-key="rowKey" :row-class-name="rowStyle" 
            :default-expand-all="defaultExpandAll" @selection-change="handleSelectionChange" @select="select" @select-all="selectAll"
            @cell-click="handleCellClick"  @sort-change="sortChangeFn" @row-click="handleRowClick" border>
            <template v-for="(col, index) in column" :key="index">
                <!---复选框, 序号 (START)-->
                <el-table-column v-if="col.type === 'index' || col.type === 'selection' || col.type === 'expand'"
                    :align="col.align" :label="col.label" :type="col.type" :fixed="col.fixed || false"
                    :index="indexMethod" :width="col.width?col.width:50" :min-width="col.minWidth" />
                <!---复选框, 序号 (END)-->

                <!-- 表单元素 -->
                <template v-else-if="com['M' + col.type] && areaAuth[col.keyNo]" >
                    <el-table-column v-if="!col.options.hide && judgeIsShow(col.keyNo)" class-name="formElement" :prop="col.keyNo" :label="t(col.label)" min-width="130">
                        <template #header v-if="col.options.rules.required">
                            <span class="headerIcon">*</span>
                            <span>{{ $t(col.label) }}</span>
                        </template>
                        <template #default="scope" >
                            <el-form-item :prop="'list.'+scope.$index+'.'+col.keyNo"  :rules="allRules[col.keyNo+scope.$index]">
                                <component :is="com['M' + col.type]" v-model="scope.row[col.keyNo]" :item="col" :pageNo="pageNo" :areaNo="areaNo"
                                :index="index" :field-form="scope.row"  :all-field-form="allFieldForm" :all-table-data="allTableData" :elementAuth="areaAuth[col.keyNo]"
                                @change="elementEventFn(col, 'change')" @keyup.enter="elementEventFn(col, 'enter')" @blur="elementEventFn(col, 'blur')" @click="eleClickFn(col, scope.row)" />
                            </el-form-item>
                        </template>
                    </el-table-column>
                </template>

                <!-- 表格列 -->
                <template v-else-if="col.type === 'tableCol'  && areaAuth[col.keyNo]" >
                    <!---弹出页面(START)-->
                    <el-table-column v-if="col.isShow && judgeIsShow(col.keyNo) && col.modalNo" :key="col.keyNo" :sortable="col.isSort ? 'custom' : false" :align="col.align || 'left'" :show-overflow-tooltip="item.config.isNewLine === false ? true : false"
                    :label="t(col.label)" :prop="col.keyNo" :width="col.width" :min-width="col.minWidth" >
                        <template #default="{ row }">
                            <span class="hasEvent" @click="openPageFn(col.modalNo, row, col.keyNo)">{{ row[col.keyNo] }}</span>
                        </template>
                    </el-table-column>
                    <!---弹出页面 (END)-->

                    <!---元素事件(START)-->
                    <el-table-column v-else-if="col.isShow && judgeIsShow(col.keyNo) && col.trigger && col.trigger != 'none' && col.actionNo" :key="col.keyNo" :sortable="col.isSort ? 'custom' : false" :align="col.align || 'left'" :show-overflow-tooltip="item.config.isNewLine === false ? true : false"
                    :label="t(col.label)" :prop="col.keyNo" :width="col.width" :min-width="col.minWidth" >
                        <template #default="{ row }">
                            <span class="hasEvent" @click="eleEventFn(col, row)">{{ row[col.keyNo] }}</span>
                        </template>
                    </el-table-column>
                    <!---元素事件 (END)-->

                    <!-- 字典 (START) -->
                    <template v-else-if="col.isShow && judgeIsShow(col.keyNo) && col.dict && col.dict != '0' ">
                        <el-table-column  :key="col.keyNo" :sortable="col.isSort ? 'custom' : false" :align="col.align || 'left'" :show-overflow-tooltip="item.config.isNewLine === false ? true : false"
                        :label="t(col.label)" :prop="col.keyNo" :width="col.width" :min-width="col.minWidth" >
                            <template #default="{ row }">
                                <span>{{ row[col.keyNo+'_label'] ? row[col.keyNo+'_label'] : row[col.keyNo] }}</span>
                            </template>
                        </el-table-column>
                    </template>
                    <!-- 字典 (END) -->

                    <!-- 默认渲染列 (START) -->
                    <template v-else>
                        <el-table-column v-if="col.isShow && judgeIsShow(col.keyNo)" :key="col.keyNo" :sortable="col.isSort ? 'custom' : false" :align="col.align || 'left'" :show-overflow-tooltip="item.config.isNewLine === false ? true : false"
                        :label="t(col.label)" :prop="col.keyNo" :width="col.width" :min-width="col.minWidth" >
                            <template #default="{ row }">
                                <span v-if="col.isHtml" class="hasEvent" @click="handleHtml(row[col.keyNo])">查看详情</span>
                                <span v-else-if="col.httpType" >
                                    <template v-if="col.httpType=='qUrl'">
                                        <div v-if="row[col.keyNo]">
                                            <template v-for="(item,index) in row[col.keyNo].split(',')" class="set-file">
                                                <span class="set_spn" style="margin-left: 10px" :title="item" @click="handelPreview(item,item)"><el-icon><Document /></el-icon></span>
                                            </template>
                                        </div>
                                    </template>
                                    <template v-if="col.httpType=='url'">
                                        <div v-if="row[col.keyNo]">
                                           <a :href="row[col.keyNo]" target="_blank">{{ row[col.keyNo] }}</a>
                                        </div>
                                    </template>
                                </span>
                                <span v-else>{{ row[col.keyNo] }}</span>
                            </template>
                        </el-table-column>
                    </template>
                    <!-- 默认渲染列 (END) -->
                </template>

                <!-- 操作列-->
                <el-table-column v-else-if="col.type === 'operateCol'" 
                    :align="col.align" :label="t(col.label)" :width="col.width" :fixed="col.fixed || false">
                    <template #default="scope">
                        <template v-for="(btnElement, bIndex) in col.buttonList" :key="bIndex">
                            <!-- // 刪除表格行,前端组件 -->
                            <template v-if="btnElement.btnType === 'delTableRow' && areaAuth[btnElement.keyNo]">
                                <el-button v-show="!btnElement.options.hide" type="text" :icon=" 'Delete' " :style="{'color':  'red !important' }"
                                    @click="handleDelRow(scope.$index)">
                                </el-button>
                            </template>
                            <template v-else-if="areaAuth[btnElement.keyNo]">
                                <el-button v-show="!btnElement.options.hide" type="text" :icon="btnElement.options.actionNo === 'deleteComponent' ? 'Delete' : btnElement.icon" :style="{'color': btnElement.options.actionNo === 'deleteComponent' ? 'red !important' : ''}"
                                    @click="handleAction(btnElement, scope.row,scope.$index,col)">
                                    {{btnElement.options.actionNo === 'deleteComponent' ? '' : t(btnElement.label) }}
                                </el-button>
                            </template>
                        </template>
                    </template>
                </el-table-column>
                <!-- 操作列 END-->

            </template>
        </el-table>
    </el-form>
        <htmlDia v-model:diaOpen="open" :content="content"></htmlDia>
        <diaPreview ref="diaEditRef" :title="title" v-model:visible="dialogVisible" :preType="preType"></diaPreview>
    </div>
</template>

2、JS部分

<script  setup>
const props = defineProps({
    pageNo: {
        type: String,
        default: ''
    },
    areaNo: {
        type: String,
        default: ''
    },
    // table的数据
    tableData: {
        type: Array,
        default: () => []
    },
    // 所有表单区域元素
    allFieldForm: {
        type: Object,
        default: () => {
            return {};
        },
    },
    // 所有表格区域元素
    allTableData: {
        type: Object,
        default: () => {
            return {};
        },
    },
    item: {
        type: Object,
        default: () => {}
    },
    column: {
        type: Array,
        default: () => []
    },
    columnsShow: {
        type: Array,
        default: () => []
    },
    option: [Object, Array],
    loading: {
        type: Boolean,
        default: false
    },
    //是否展示表格树型结构
    rowKey: {
        type: String,
        default: ''
    },
    defaultExpandAll: {
        type: Boolean,
        default: false
    },
    rowStyle: {
        type:Boolean,
        default:false
    },
    // 当前区域的权限
    areaAuth: {
        type: Object,
        default: () => {
            return {};
        },
    }
})

const {pageNo, areaNo, item, column, tableData, allFieldForm, allTableData, areaAuth} = toRefs(props)
const {trigger, actionNo, conditionArea, serveAreaNo } = item.value

const emit = defineEmits(['selection-change','select-all', 'select','row-click', 'cell-click', 'command', 'size-change', 
'current-change','row-class-name', 'sortChange', 'openPage', 'clickBtn', 'update:tableData','tableFormValid'])

const allRules = reactive({})
const tableFrom = ref('')
const fromData = ref({
    list:[]
})

watch(()=>tableData.value,(value)=>{
 
    fromData.value.list = tableData.value
    initRuleFn()
    
}, { deep: true })

// 生成校验规则
const initRuleFn = () => {
    console.log('column.value2222======', column.value)
    for(let i=0; i< column.value.length; i++ ){
        const element = column.value[i]
        const { type, label, keyNo, options} = element

        console.log('element111======', element)

        if(['input', 'select', 'dateRange', 'datetimerange', 'date', 'datetime', 'checkbox', 'upload', 'richtextEditor'].includes(type)){
            // 元素校验
            const { rules, validParamList } = options
            const {data, total} = allTableData.value[areaNo.value]
            let tableData = JSON.parse(JSON.stringify(data))
            

            // 将表格该列校验重新生成
            tableData.forEach( (row, index) => {
                allRules[keyNo+index] = []
            })
            // 必填 
            if(rules && rules.required && !rules.hasRequiredFactor){
                // 条件必填为空
                tableData.forEach( (row, index) => {
                    allRules[keyNo+index]=[{ required: true, message: t(label) + t('element132'), trigger: ["blur", "change"] }]
                })
            }else if(rules && rules.required && rules.hasRequiredFactor){
                const words = escape2Html(rules.hasRequiredFactor)
                const reg = /[#\$%\^&\*【】@!!¥?|‘;:”“'。,、?<>+=:-]+/g
                const reg1 = /[a-zA-Z0-9]+/g//筛选特殊字符串中的元素别名

                console.log('words1111======', words)

                if(words.indexOf('!=')>-1||words.indexOf('==')>-1||words.indexOf('=')==-1||words.indexOf('>')>-1||words.indexOf('<')>-1) {
                    
                    //日期校验
                    if(words.indexOf('date')>-1) {
                        const nwds = words.replace('date:','')
                        console.log('nwds======',nwds)
                        const filteWds = nwds.replace(reg,',')//过滤特殊字符
                        const WdsList = filteWds.split(',')
                        console.log('filteWds=====',WdsList.length)
                        let fwds = nwds.substr(nwds.length-1,1)//获取字符串最后一个字段
                        
                        const curDate = new Date()  //获取当前日期
                        if(nwds.indexOf('c')>-1 || nwds.indexOf('C')>-1) {//存在当前日期
                            if(WdsList.length==3&&nwds.indexOf('-')>-1) {
                                let num = WdsList[2].replace(fwds,'')//日期计算天数
                                let diff = 0
                                Object.keys( aObj ).forEach( areaKey => {
                                    const aItem = aObj[areaKey]
                                    if(aItem[WdsList[1]]) {
                                        if(['M','Y'].includes(fwds)) {
                                            diff = getDateYMDiff(aObj[areaKey][WdsList[1]],'2023/08/25',fwds)
                                        }
                                        console.log('diff======',diff)
                                    }
                                })
                                let bol = false
                                if(diff < Number(num) ){
                                    bol = true
                                }
                                const yObj = {
                                    'M':'月',
                                    'Y':'年'
                                }
                                if(bol) {
                                    const validateFc = (rule, value, callback) => {
                                        if (bol) {
                                            callback(new Error( t(label) + '必须大于等于'+num + yObj[fwds]))
                                        } else if (!bol) {
                                            callback()
                                        }
                                    }
                                    allRules[keyNo] = [{ required: bol, validator: validateFc, trigger: ["blur", "change"] }]
                                }
                                
                            }
                        }
                        
                    }else {//公式计算校验
                        let eList = words.match(reg1) // 元素列表
                        const wordsList = words.split(',') // 公式
                        if(wordsList.length>0) {
                            console.log('eList=====',eList, wordsList)

                            tableData.forEach( (row, index) => {
                                let awords = []
                                
                                wordsList.forEach(wd=>{
                                    Object.keys(row).forEach(key=>{
                                        if(eList.includes(key)) {
                                            if(['',null].includes(row[key])) {
                                                row[key] = 0
                                            }
                                            wd = wd.replaceAll(key,row[key])
                                            awords.push(wd)
                                        }
                                    })
                                })
                                console.log('awords=====',awords)
                                awords.forEach(d=>{
                                    let bol = eval(d)
                                    if([true].includes(bol)) {
                                        allRules[keyNo+index]=[{ required: true, message: t(label) + t('element132'), trigger: ["blur", "change"] }]
                                    }
                                    
                                })
                            })
                        
                        }
                    }
                    
                }
            }
        }
    }
    console.log('allRules======', allRules)

}

//日期比较
function timeCompareFn(value,item,labels,form,curD='') {
  const formulaObj = {
	'1':'等于',
	'2':'大于',
	'3':'小于',
	'4':'indexOf',
	'7':'indexOf',
	'10':'小于等于',
	'11':'==null',
	'12':'!=null',
	'13':'不等于',
	'9':'大于等于'
  }
  let objKey = ''
  let formula = item['conditionFormula']//比较方式
  let compareValues = form[item.compareValue]//比较值
  if(curD) {
    compareValues = curD
  }
  let labelCpare = ''
  let cols = column.value.find(kd=>kd.keyNo == item.compareValue) || ''
  if(cols) {
    labelCpare = t(cols.label)
  }
  //比较值compareValue
  if(formula&&formula != 'indexOf' && compareValues) {
    if (!value) {
      objKey = ``
    }else{
		if(!compareValues) {
            objKey = `请输入${labelCpare}`
		}else{
			const d1 =compareValues? compareValues.replace(/-/g, '/'):''//比较值
			const d2 = value.replace(/-/g, '/')//填写值
			let curD1 = new Date(d1).getTime()
			let curD2 = new Date(d2).getTime()
			console.log('curD1=====',curD1)
			console.log('curD2=====',curD2)
			let flag = true
			if(formula=='1') {
				 flag = curD2 == curD1?true:false
			}else if(formula=='2') {
				 flag = curD2 > curD1?true:false
			}else if(formula=='3') {
				 flag = curD2 < curD1?true:false
			}else if(formula=='10') {
				 flag = curD2 <= curD1?true:false
			}else if(formula=='13') {
				 flag = curD2 != curD1?true:false
			}else if(formula=='9') {
				 flag = curD2 >= curD1?true:false
			}
			if(!flag) {
                objKey = t(labels)+formulaObj[formula]+labelCpare
			}
        }
    }
  } 
  return objKey
}

function validate(callback) {
   return tableFrom.value.validate( res => {
        console.log('res===2222', res);
        return res
    })
}

defineExpose({
    validate
})
</script>

3、父页面

事件按钮触发 表单表格组件 的校验

<Table class="setTable" v-if="item.config.type==='list'" :ref="(el) => setItemRef(el, item.keyNo)" v-show="formatInitShow(item)" :key="item.keyNo" :option="option" :item="item" :columnsShow="allTableCol[item.keyNo]" :column="item.columns" 
            v-model:table-data="allAreaDate[item.keyNo].data" :all-field-form="fieldForm" :all-table-data="allAreaDate" :pageNo="pageConfig.pageNo" :areaNo="item.keyNo" :areaAuth="pageAuth[item.keyNo]"
            @cell-click="handleCellClick" @selection-change="handleSelectionChange($event, item.keyNo)" @select-all="selectAll($event, item.config, item.keyNo)"
            @sort-change="handleSortChange" @openPage="openPageFn" @clickBtn="clickBtnFn" @tableBtn="eventFn" @delTableRow="delTableRowFn">
               <template #userStatus>
                  <el-table-column label="状态" align="left" min-width="80">
                     <template #default="scope">
                        <el-switch v-model="scope.row.userStatus" active-value="0" inactive-value="1"
                           @click="handleStatusChange(scope.row)"></el-switch>
                     </template>
                  </el-table-column>
               </template>
            </Table>


<script setup name="templateOne">
// 区域对应组件的ref
function setItemRef(el, keyNo) {
   if (el && keyNo) {
      allRefs[keyNo] = el
   }
   console.log('allRefs==========', allRefs)
}

/** 新增修改,保存按钮 */
async function submitForm(pageNo, areaNo, keyNo, serveArea, actionNo, elementEvent, tableRowIndex) {
   const { areaVoList } = configParamJson.value

   // 打印组件不校验  
   if(actionNo === 'PrintTemplateComponent'){
      addClickBtnFn(pageNo, areaNo, keyNo, serveArea, actionNo, elementEvent, tableRowIndex)
      return
   }

   // 校验
   for(let i=0; i<serveArea.length; i++){
      let item = serveArea[i]

      if(fieldForm[item]){
         for(let j=0; j<areaVoList.length; j++){
            const areaItem = areaVoList[j]
            const {areaNo, areaType, elementVoList} = areaItem

            // 非标题区域
            if(areaNo === item && areaType !=='titleArea' && allRefs[item]){
               // 表单校验
               let valid = await allRefs[item].validate()
               // 校验不通过
               if(!valid){
                  proxy.$modal.msgError(t('element207'))
                  return
               }
            }
         }
      }else if(allAreaDate[item]){
         // 列表校验
         for(let j=0; j<areaVoList.length; j++){
            const areaItem = areaVoList[j]
            const {areaNo, areaType, elementVoList} = areaItem

            console.log('areaItem====', areaItem)
            // 遍历表格区域内元素是否必填
            if(areaNo === item && areaType ==='tableArea'){
               // 表单校验
               let valid = await allRefs[item].validate()
               // 校验不通过
               if(!valid){
                  proxy.$modal.msgError(t('element207'))
                  return
               }
            }

         }
      }
   }

   // 校验通过
   btnLoading.value = true
   addClickBtnFn(pageNo, areaNo, keyNo, serveArea, actionNo, elementEvent, tableRowIndex)
   cancel()
  
}
</script>

4、总结

  • <el-form :model="fromData" ref="tableFrom">在el-table外层
  • el-form 绑定 :model=“fromData”,el-table 的:data="fromData.list"要有层级关系
  • 校验的prop一定要按照,:prop="'list.'+scope.$index+'.'+col.keyNo"格式,意思是 list列表内的 第几行 的 什么字段
`<el-table-column :prop="col.keyNo" :label="t(col.label)" min-width="130">
    <template #default="scope" >
        <el-form-item :prop="'list.'+scope.$index+'.'+col.keyNo"  :rules="allRules[col.keyNo+scope.$index]">
            <component :is="com['M' + col.type]" v-model="scope.row[col.keyNo]" :item="col"  @click="eleClickFn(col, scope.row)" />
        </el-form-item>
    </template>
</el-table-column>`
  • 校验的触发时机为trigger: ["blur", "change"]
allRules[keyNo+index]=[{ required: true, message: t(label) + t('element132'), trigger: ["blur", "change"] }]
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue3 Element Plus是一套基于Vue3的UI组件库提供了丰富的组件和功能,其包括了Form表单组件。在Element Plus,可以通过动态校验来实现同一字段的表单动态校验。 在Vue3 Element Plus,可以使用`el-form`组件来创建表单,通过`el-form-item`组件来包裹表单项。要实现同一字段的表单动态校验,可以使用`rules`属性来定义校验规则。 首先,需要在Vue组件定义表单数据和校验规则。例如: ```javascript data() { return { form: { field1: '', field2: '' }, rules: { field1: [ { required: true, message: '字段1不能为空', trigger: 'blur' }, // 其他校验规则 ], field2: [ { required: true, message: '字段2不能为空', trigger: 'blur' }, // 其他校验规则 ] } } } ``` 然后,在模板使用`el-form`和`el-form-item`组件来创建表单,并绑定数据和校验规则。例如: ```html <template> <el-form :model="form" :rules="rules" ref="form"> <el-form-item label="字段1" prop="field1"> <el-input v-model="form.field1"></el-input> </el-form-item> <el-form-item label="字段2" prop="field2"> <el-input v-model="form.field2"></el-input> </el-form-item> </el-form> </template> ``` 最后,可以通过调用`validate`方法来触发表单校验。例如: ```javascript methods: { submitForm() { this.$refs.form.validate((valid) => { if (valid) { // 校验通过,提交表单 } else { // 校验不通过,处理错误信息 } }); } } ``` 这样,就可以实现同一字段的表单动态校验了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值