elementUi el-table组件header插槽 嵌套其他组件 视图不渲染问题解决方案(使用render-header)

817 阅读1分钟

image.png

    如图一个由elementUI el-table组件生成的一个表格,需要在表格头部,完成情况列增加一个图标,点击后浮动一个轻量级的弹层,选择单选项,点击确定,实现批量设置完成情况的功能。一般来说,这种需求,可以通过el-table的头部插槽+el-popover弹出框来实现。结果遇到了一个难题,不论怎么尝试,渲染出来的弹出框中的单选框点击没有任何选中效果,使用vue插件查看数据,v-model对应的值数据确实发生了改变,并且重新打开页面,弹出框的选项才发生变化。期间尝试过使用input框来绑定数据,不论是放在el-popover组件中,还是直接放在el-popover外面,均无法生效。

    最后使用render-header的方式解决了问题。

image.png

    为了方便使用,将表格头部插槽内容单独抽取组件。

表格部分代码:

<el-table-column prop="paramLevelId" :render-header="renderHeader" :label="qualityCheckEvalLevelName" width="100" align="center">
  <template slot-scope="{ row, $index }">
    <div class="spread">
      <div v-show="controlParam.btnName !=='检查' && controlParam.btnName !=='提交'" :style="{color:getColor(row.paramLevelId)}">
        {{ getLevelName(row.paramLevelId) }}
      </div>
      <el-tooltip v-model="row.evalParamLevelIdTips" class="item" :disabled="!row.evalParamLevelIdTips" effect="dark" :content="'请选择'+qualityCheckEvalLevelName" placement="top-end">
        <el-select v-show="controlParam.btnName ==='检查' || controlParam.btnName ==='提交'" :ref="`evalParamLevelId${row.number}`" v-model="row.paramLevelId" :placeholder="'请选择'+qualityCheckEvalLevelName" @change="changeTextColor($event,`evalParamLevelId${row.number}`)">
          <el-option v-for="item in paramLevelList" :key="item.id" :label="item.levelName" :value="item.id" v-html="'<span style=color:'+item.color+'>'+item.levelName+'</span>'" />
        </el-select>
      </el-tooltip>
    </div>
  </template>
</el-table-column>

renderHeader(h, { column, $index }, index) {
  return (
    <ParamLevelRenderHeader qualityCheckEvalLevelName={this.qualityCheckEvalLevelName} levelCheckModeParamValue={this.levelCheckModeParamValue} controlParam={this.controlParam} paramLevelList={this.paramLevelList}/>
  )
}
// 相对定位 需要设置overflow 否则看不到popover弹出框
.checkTableInfo .el-table__header-wrapper{
      overflow: visible !important;
    }
.checkTableInfo .el-table th{
      overflow: visible !important;
    }
.checkTableInfo .el-table .cell{
      overflow: visible !important;
 }

组件代码:

<template>
  <div class="d-flex" style="justify-content: center;align-items: center;position: relative">
    <span class="flex">{{ qualityCheckEvalLevelName }}</span>
    <i v-if="(controlParam.btnName ==='检查' || controlParam.btnName ==='提交') && levelCheckModeParamValue === 'allCheck'" class="el-icon-set-up flex" style="font-size: 18px;cursor: pointer" @click.stop="showBatchParamLevel" />
    <el-popover
      v-if="(controlParam.btnName ==='检查' || controlParam.btnName ==='提交') && levelCheckModeParamValue === 'allCheck'"
      ref="batchParamLevel"
      class="batchParamLevel"
      placement="bottom"
      trigger="click"
    >
      <div @click.stop>
        <div style="text-align: center;" class="font-14">批量设置</div>
        <div>
          <div>
            <el-radio-group v-model="batchSettingParamLevelId" style="padding: 0;margin-top:10px;width: 100%;">
              <el-radio v-for="(item,index5) in paramLevelList" :key="index5" style="margin: 5px 0;text-align: center;width: 90%" :label="item.id">{{ item.levelName }}</el-radio>
            </el-radio-group>
          </div>
        </div>
        <div class="d-flex j-center">
          <el-button class="mt-1" type="primary">确定</el-button>
          <el-button class="mt-1" type="primary">重置</el-button>
        </div>
      </div>
    </el-popover>
  </div>
</template>

<script>
export default {
  name: 'ParamLevelRenderHeader',
  props: {
    qualityCheckEvalLevelName: { // 分级名称
      type: String,
      default: ''
    },
    levelCheckModeParamValue: {
      type: String,
      default: 'questionCheck'
    },
    controlParam: { // 控制参数
      type: Object,
      default: () => ({ btnName: '查看' })
    },
    paramLevelList: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {
      batchSettingParamLevelId: ''
    }
  },
  methods: {
    /**
     * 显示批量设置质控评价分级
     */
    showBatchParamLevel() {
      if (this.$refs['batchParamLevel']) {
        this.$refs['batchParamLevel'].doShow()
        document.addEventListener('click', this.closePopover)
      }
    },
    closePopover() {
      if (this.$refs['batchParamLevel']) {
        this.$refs['batchParamLevel'].doClose()
        document.removeEventListener('click', this.closePopover)
      }
    }
  }
}
</script>

<style>
</style>

代码解析:

1、采用相对定位布局,使得滚动时跟随表格滚动,需要增加额外样式,处理overflow,否则弹出框无法显示。

2、点击图标弹出popover,点击空白处隐藏弹出框,需要在popover中最大的div上加上@click.stop阻止冒泡,否则点击弹出框中的内容也会关闭弹出框。