el-table中 el-popover 性能优化

场景:在 el-table 中使用 el-popover ,出现了 loading 加载卡顿的问题,接口返回的数据的时间大概是 140ms ,所以不是接口慢的原因;通过对表中结构的逐步排查,发现是表中的 某一行 所影响的;并且 其中含有 el-popover;因为 el-popover 会渲染出真实的 dom 元素 所以在页面渲染的时候会出现el-table loading 卡顿的情况。

原来的代码是这样的

jsx 复制代码
<ElTable v-loading="loading" :data="tableData" @selection-change="handleSelectionChange" size="small"
                 show-overflow-tooltip @row-dblclick="handleViewDetail" ref="tableRef"
                 :height="tableHeight" highlight-current-row @current-change="handleCurrentRowChange"
                 :row-class-name="tableRowClassName"
                 @sort-change="sort_change"
                 :cell-style="rowClassName"
                 :row-style="{height: '30px'}"
                 :header-cell-style="headerClassName"
        >
//...
	<el-table-column prop="remark" :label="$t('common.remark')" width="100">
		<template #default="scope">
            <el-popover :visible="scope.row.visible" placement="top" trigger="click" :width="204">
              <el-input v-model="scope.row.remark" style="width: 180px;"
                        :placeholder="$t('common.email.setBlockSize')"/>
              <div style="text-align: right; margin: 16px 0 0 0;">
                <el-button size="small" text @click="() => {
                              scope.row.visible = false;
                              scope.row.remark = '';
                            }">{{ $t('common.sss16') }}
                </el-button>
                <el-button size="small" type="primary" @click="() => {
                              scope.row.visible = false;
                              setRemark(scope.row.mailId, scope.row.remark)
                            }"
                >{{ $t('common.confirm') }}
                </el-button
                >
              </div>
              <template #reference>
                <el-icon @click="scope.row.visible = true" :color="scope.row.remark ? '#40a9ff' : '#dddddd'">
                  <el-tooltip
                      v-if="scope.row.remark"
                      class="box-item"
                      :content="scope.row.remark"
                      placement="right"
                  >
                    <Memo/>
                  </el-tooltip>
                  <Memo v-else/>
                </el-icon>
              </template>
            </el-popover>
          </template>
	</el-table-column>

//...
</ElTable>

解决办法:因为每次都要渲染真实dom;所以可以将 el-popover 抽离 就像 el-dialog 一样;只不过这里有特别的地方是------每行的数据都是不一样的,还需要动态展示每行的数据。

jsx 复制代码
<el-table-column prop="remark" :label="$t('common.remark')" width="100">
            <template #default="scope">
              <el-icon :ref="(el) => (refMap[`${scope.row.id}`] = el)"
                       @click="handleRef(refMap[`${scope.row.id}`], scope.row)"
                       :color="scope.row.remark ? '#40a9ff' : '#dddddd'">
                <el-tooltip
                    v-if="emailListCheckoutTarget.remark"
                    class="box-item"
                    :content="emailListCheckoutTarget.remark"
                    placement="right"
                >
                  <Memo/>
                </el-tooltip>
                <Memo v-else/>
              </el-icon>

            </template>
          </el-table-column>

抽离的 el-popover

jsx 复制代码
      <el-popover
          virtual-triggering
          :virtual-ref="tempRef"
          v-model:visible="visiblePopover"
          placement="top"
          :width="204"
          trigger="click"
          :popper-options="{
              modifiers: [{
		          name: 'offset',
		          options: {
			          offset: [8, 8]
		          }
	        }]
	    }">
        <el-input v-model="emailListCheckoutTarget.remark" style="width: 180px;"
                  :placeholder="$t('common.email.setBlockSize')" @keydown.enter.native.stop="okPopover"/>
        <div style="text-align: right; margin: 16px 0 0 0;">
          <el-button size="small" text @click.stop="cancelPopover">{{ $t('common.sss16') }}
          </el-button>
          <el-button size="small" type="primary" @click.stop="okPopover"
          >{{ $t('common.confirm') }}
          </el-button
          >
        </div>
      </el-popover>

最重要的一点是,采用这种方式,会出现 重复点击该列的目标对象的时候,会出现 visiblePopover 和 trigger 不同步的问题,表现为 el-popover 闪烁一次;所以需要在用户点击的时候重置 el-popover的显隐状态

jsx 复制代码
 	  //真实dom数组
		const refMap = ref([])
    //目标dom对象
    const tempRef = ref(null)
    //控制 el-popover 的显隐状态
    const visiblePopover = ref(false)
    //选中的行数据
    const emailListCheckoutTarget = ref({})
    
    //触发方法
    const handleRef = (ref, item, type) => {
      tempRef.value = ref
      //重置 el-popover 显隐状态
      visiblePopover.value = false;
      setTimeout(() => {
        visiblePopover.value = true;
      }, 200)

      emailListCheckoutTarget.value = item;
      localStorage.setItem('targetItem', JSON.stringify(item.remark))
    }

其次还要考虑到什么时候渲染指定的行内容;使用 鼠标 移入、移出 事件;

jsx 复制代码
    // 这里是开始点
    const mouseEnters = throttle((row) => {
		//localStorage.getItem("targetItem") 这里是特殊处理,可以根据实际情况处理
      if (localStorage.getItem("targetItem") !== row.remark) {
        visiblePopover.value = false
      }
      if (emailListCheckoutTarget.value.remark !== '') {
        emailListCheckoutTarget.value = row;
      }
    }, 300)

    const mouseLeaves = throttle((row) => {
      if (localStorage.getItem("targetItem") === row.remark) {
        // 防止popover 消失
        visiblePopover.value = false;
      }
    }, 300)

这是两个方法:提交数据;取消提交

jsx 复制代码
  const cancelPopover = () => {
      visiblePopover.value = false;
      emailListCheckoutTarget.value.remark = ''
    }

    const okPopover = () => {
	//这是提交到后端
      setRemark(emailListCheckoutTarget.value.id, emailListCheckoutTarget.value.remark)
      emailListCheckoutTarget.value = {};
      visiblePopover.value = false;
    }

经过上面的一顿操作后,肉眼可见的速度提高了,大约优化了 0.5s 左右。

相关推荐
前端拾光者33 分钟前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
木子02041 小时前
前端VUE项目启动方式
前端·javascript·vue.js
endingCode2 小时前
45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题
javascript·macos·typescript
运维-大白同学2 小时前
将django+vue项目发布部署到服务器
服务器·vue.js·django
Myli_ing3 小时前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
I_Am_Me_3 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
℘团子এ3 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z3 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
星星会笑滴3 小时前
vue+node+Express+xlsx+emements-plus实现导入excel,并且将数据保存到数据库
vue.js·excel·express
前端百草阁4 小时前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript