使用element-ui中的el-form和el-table嵌套实现表格内容编辑并提交表格表单数据校验

vue3+element-plus: el-table表格动态添加或删除行,无校验,支持下拉选择

https://blog.csdn.net/m0_58953167/article/details/134895241

点击空白处保存的能力

https://www.yii666.com/blog/214446.html

判断点击区域是否为表格区域

该功能点通过 contains 接口实现。判断条件为 tableDom.contains(target) ;该接口可以判断target是否为tableDom的子节点。

// 首先通过addEventListener 传入点击的dom区域
document.addEventListener(
 "click",
 e => {
  this.judgeClickDom(e);
 },
 false
 );
// this.bindClick是为了取消监听,下文会进行描述

// 判断点击是否为table区域
judgeClickDom(e) {
 const { target } = e;
 let tableDom = document.getElementsByClassName("table");
 
// getElementsByClassName获取到的是数组,一定要有下标不然会报错

// 如果我们点击的区域在表格外保存数据
 if (!tableDom[0].contains(target)) {
 this.saveTableData();
 }
},

校验

Vue+element实现el-table行内编辑并校验
https://blog.csdn.net/qq_43145310/article/details/129048397

动态表单的校验和提交

使用element-ui中的el-form和el-table嵌套实现表格内容编辑并提交表格表单数据校验(可以对勾选到的表格内容必填校验+勾选框)
https://blog.csdn.net/weixin_48612307/article/details/132445304

最终的组件布局如下

<el-form ref="formRef" :model="ruleForm" label-width="120px" class="demo-dynamic" :rules="rules">
  <el-table :data="ruleForm.tableData" border style="width: 100%;margin: 0 auto;" @cell-click="editRow">
            <el-table-column label="序号" align="center" width="100">
              <template #default="scope">
                <span>{{ scope.$index + 1 }}</span>
              </template>
            </el-table-column>
            <el-table-column label="字段英文名称" align="center" width="200">
              <template #default="scope">
                <el-form-item :prop="`tableData.${scope.$index}.enField`" :rules="rules.enField">
                //<el-form-item :prop="`ruleForm.tableData.${scope.$index}.enField`" :rules="rules.enField"> 
                  <el-input v-show="scope.row.edit" v-model="scope.row.enField" size="small"></el-input>
                  <span v-show="!scope.row.edit" >{{ scope.row.enField }}</span>
                </el-form-item>
              </template>
            </el-table-column>
  </el-table>
</el-form>

部分代码如下

<template>
  <div style="margin-bottom: 50px;">


    <el-form ref="formRef" :model="ruleForm" label-width="120px" class="demo-dynamic" :rules="rules">
      <el-card>
        <template #header>
          <div class="card-header flex justify-between">
            <span>表信息</span>
          </div>
        </template>
        <el-form-item label="表中文名" prop="cnname">
          <el-input v-model="ruleForm.cnname" />
        </el-form-item>
        <el-form-item label="表英文名" prop="enname">
          <el-input v-model="ruleForm.enname" />
        </el-form-item>
      </el-card>
      <el-card>
        <template #header>
          <div class="card-header flex justify-between">
            <span>字段信息</span>
            <el-button @click="addTableData" type="primary">添加字段</el-button>
          </div>
        </template>
        <div class="jiegou">
          <el-table :data="ruleForm.tableData" border style="width: 100%;margin: 0 auto;" @cell-click="editRow"  :class="editClass?'':'noEditClass'">
            <el-table-column label="序号" align="center" width="100">
              <template #default="scope">
                <span>{{ scope.$index + 1 }}</span>
              </template>
            </el-table-column>
            <el-table-column label="字段英文名称" align="center" width="200">
              <template #default="scope">
                <el-form-item label-width="0" :prop="`tableData.${scope.$index}.enField`" :rules="rules.enField" >

                  <el-input v-show="scope.row.edit" v-model="scope.row.enField"></el-input>
                  <span v-show="!scope.row.edit" class="flex-1">{{ scope.row.enField }}</span>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="字段中文名称" align="center" width="200">
              <template #default="scope">
                <el-form-item label-width="0" :prop="`tableData.${scope.$index}.enField`" :rules="rules.enField" >

                  <el-input v-show="scope.row.edit" v-model="scope.row.enField"></el-input>
                  <span v-show="!scope.row.edit" class="flex-1">{{ scope.row.enField }}</span>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="字段类型" align="center" width="200">
              <template #default="scope">

                <el-form-item label-width="0" :prop="`tableData.${scope.$index}.enField`" :rules="rules.enField" >
                  <el-select v-show="scope.row.edit" v-model="scope.row.enField"  clearable>
                    <el-option v-for="item in fieldType" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                  <span v-show="!scope.row.edit" class="flex-1">{{ scope.row.enField }}</span>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="主键" align="center" width="200">
              <template #default="scope">
                <el-form-item label-width="0" :prop="`tableData.${scope.$index}.enField`" :rules="rules.enField" >

                  <el-select v-show="scope.row.edit" v-model="scope.row.enField"  clearable>
                    <el-option v-for="item in boolSelect" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                  <span v-show="!scope.row.edit" class="flex-1">{{ scope.row.enField }}</span>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="允许为空" align="center" width="200">
              <template #default="scope">
                <el-form-item label-width="0" :prop="`tableData.${scope.$index}.enField`" :rules="rules.enField" >

                  <el-select v-show="scope.row.edit" v-model="scope.row.enField"  clearable>
                    <el-option v-for="item in boolSelect" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                  <span v-show="!scope.row.edit" class="flex-1">{{ scope.row.enField }}</span>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="字段注释" align="center" width="200">
              <template #default="scope">
                <el-form-item label-width="0" :prop="`tableData.${scope.$index}.enField`" :rules="rules.enField" >

                  <el-input v-show="scope.row.edit" v-model="scope.row.enField"></el-input>
                  
                  <span v-show="!scope.row.edit" class="flex-1">{{ scope.row.enField }}</span>
                </el-form-item>
              </template>
            </el-table-column>

            <el-table-column label="操作" align="center" fixed="right" min-width="200">
              <template #default="scope">
                <el-button @click="deleteTableData(scope.row)" link icon="Delete" type="primary">删除</el-button>
              </template>
            </el-table-column>
          </el-table>

        </div>
        <div class="shuju">

        </div>

      </el-card>

    </el-form>
    <div class="footer flex justify-center">
      <el-button @click="onSubmit" type="primary">保存</el-button>
      <el-button>取消</el-button>
    </div>
  </div>
</template>
      
<script setup>
import { reactive, ref, onMounted, onUnmounted } from 'vue';
import { addData, fieldType, boolSelect } from './mock';

const tableData = ref(addData)
const editClass=ref(false)
// 新增一行
const addTableData = () => {
  const newRow = {
    // index:tableData.value?.length,
    type: null,
    days: null,
    amount: null,
    edit: true
  }
  tableData.value.push(newRow)
}
// 删除
const deleteTableData = (row) => {
  console.log('删除', row)
  const index = tableData.value.indexOf(row);
  if (index !== -1) {
    tableData.value.splice(index, 1);
  }
}

const ruleForm = reactive({
  cnname: '中文名',
  enname: '英文名',
  tableData: tableData

})

const rules = reactive({
  cnname: [
    { required: true, message: '请输入', trigger: 'blur' },
    { min: 3, max: 5, message: '长度是3到5个字符', trigger: 'blur' },
  ],
  enname: [
    { required: true, message: '请输入', trigger: 'blur' },
    { min: 3, max: 5, message: '长度是3到5个字符', trigger: 'blur' },
  ],
  enField: [
    { required: true, message: '请输入', trigger: 'blur' },
    { min: 3, max: 5, message: '长度是3到5个字符', trigger: 'blur' },
  ],
})

const editRow = (row) => {
  editClass.value=true
  const index = tableData.value.indexOf(row);
  if (index !== -1) {
    tableData.value[index].edit = true;
  }
}
// const cellBlur=(index)=>{
//   // console.log('index',index)
//   // tableData.value[index].edit=false
// }
onMounted(() => {
  window.addEventListener('click', judgeClickDom)
})

onUnmounted(() => {
  // 移除事件监听
  window.removeEventListener('click', judgeClickDom)
})

// 判断是否点击了table
const judgeClickDom = (e) => {

  const { target } = e;
  let tableDom = document.getElementsByClassName("el-table");

  // getElementsByClassName获取到的是数组,一定要有下标不然会报错
  console.log('tableDom[0].contains(target)', tableDom[0].contains(target))
  // 如果我们点击的区域在表格外保存数据
  if (!tableDom[0].contains(target)) {
    
    // this.saveTableData();
    formRef.value.validate((valid) => {
      if (valid) {
        editClass.value=false
        tableData.value = tableData.value.map(item => {
          item.edit = false
          return item
        })
      } else {
        console.log('check false!')
        return false
      }
    })

  }
}
const formRef = ref(null)
const onSubmit = () => {
  // console.log('submit!')
  formRef.value.validate((valid) => {
    if (valid) {
      console.log('submit!')
    } else {
      console.log('error submit!')
      return false
    }
  })
}

</script>



      
<style lang="less" scoped>
.box {
  position: relative;
}

.box .icon {
  position: absolute;
  bottom: 10px;
  right: 19px;
}

.el-table.noEditClass .el-form-item {
  margin-bottom: 0px;
}



.footer {
  padding: 10px;
  position: fixed;
  bottom: 0;
  box-sizing: border-box;
  width: 100%;
  background: #fff;
  border-top: 1px solid #e2e2e2;
  z-index: 100;
}
</style>

posted @ 2024-01-30 14:30  风意不止  阅读(3529)  评论(0编辑  收藏  举报