背景
仍然是上一篇文章里提到的 “自定义列表项” 需求暴露出来的问题,就是用户在对列表项进行自定义配置之后,列表此时就需要展示用户配置的列表项,由于列表接口之前已经返回了我所有数据,所以这里不需要再请求列表接口,直接从之前的数据里筛选出用户选择的列及数据,然后展示出来即可。
问题
功能做完后,在测试阶段,我发现在进行 “自定义列表项” 操作后,表格展示的列数据出现重复,还伴有字段值和字段名不匹配的问题。但是刷新列表或者重新请求列表接口后就好了。
分析
看到这种情况,我首先怀疑是表格组件没有重新渲染导致的(而查询列表的时候,表格组件我加了 v-if
会触发重新渲染),于是首先检查自定义列表保存后的数据是否正确。
经过调试,发现数据是正常的,只是页面展示有问题。
这种情况首先会让人联想到的就是 Vue.$set()
这个方法,手动响应化当前的值,触发页面重新渲染,联系到这里就是怎么让表格组件重新渲染。
经过搜索以及以往的经验,找到以下可能有用的方案:
- 使用表格自带的方法
doLayout()
重新触发表格渲染,一般这样使用this.$refs.table.doLayout()
; - 通过一个布尔值和
v-if
指令结合来触发表格重新渲染,也就是在数据改变后,改变这个布尔值,通过v-if
判断这个布尔值来触发重新渲染; - 给当前组件或包装容器添加一个
key
属性,指定一个唯一的值,然后数据改变后,我们更新这个唯一值,这样 Vue 会自动重新渲染该组件。
基于目前的项目,我选择了第 3 种方案,主要有2个原因:
1、首先 table 组件被包装了多层,不太方便通过 $ref
去查找 doLayout
方法;
2、其次,第2种侵入性较大,怕影响现有逻辑;
如果前面2种不好用,也可以和我一样用第3种,这个方法百试不爽。主要分3步来解决:
解决
1、准备一个生成唯一值的工具方法,这里直接使用了我之前收藏的基于 URL.createObjectURL()
的唯一值生成方法,见文章【收藏】一波实用的JS小技巧。
// 获取唯一id
export function getUUid() {
const r = URL.createObjectURL(new Blob());
return r.substr(r.lastIndexOf("/") + 1, r.length - 1);
}
2、在页面引入该工具方法,并在 data
种定义一个变量来存储它,这里以 uuid
为例。
import { getUUid } from "@/utils/index"; // 引入getUUid
// data 中定义uuid
data() {
return {
uuid: getUUid()
}
}
3、我对应的表格组件或者包装元素添加一个 key
属性,值为我们定义的唯一值 uuid
。
<div v-if="tableData.length" class="tab-back">
<table-com
:key="uuid"
:column-info="columnList"
:table-data="tableData"
:show-sort="true"
sort-width="80px"
:show-sle="false"
:total-count="totalCount"
:page-size="pageSize"
:current-page="pageNo"
@handlePageChange="handlePageChange"
></table-com>
</div>
4、在修改表格数据逻辑的后面,我们再次生成一次随机值,并赋给 uuid
。
this.uuid = getUUid();
经过以上操作后,我再次去尝试复现之前的问题,已经没有出现了,之前操作3次左右基本就会复现,现在操作几十次也没有再复现。
至此,问题解决,该方案同样适用于其它同类场景,不限组件,本质是利用了 vnode
的 key
来更新 DOM
。
感受
有时候一个简单需求可能就会暴露不少问题,自测时可能并不见得发现或者测试次数不够都有可能让该缺陷上到生产环境,这是很致命的。
要多一点点细心,边界情况多是多,我们不可能覆盖每一个场景,但是可以花时间覆盖常见的场景。
评论区