需求场景
头部使用的tab标签栏,标签栏下面是通过子标签key值控制对应的显示内容,内容中包含的业务数据表格,简易代码如下:
#html
<div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="首页" name="1"></el-tab-pane>
<el-tab-pane label="配置管理" name="2"></el-tab-pane>
<el-tab-pane label="角色管理" name="3"></el-tab-pane>
</el-tabs>
</div>
# 标签对应的内容
<div v-if="activeName === '1'">
<el-table
:data="tableData"
height="250"
border
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection"width="55"></el-table-column>
<el-table-column prop="date" label="日期" width="180"></el-table-column>
</el-table>
</div>
<div v-if="activeName === '2'">
业务表格二
</div>
<div v-if="activeName === '3'">
业务表格三
</div>
想要实现的场景就是通过切换tab,获取不同的业务数据并渲染到页面上,代码和业务逻辑上都没有问题,由于业务需求需要批量操作业务数据,因此给表格添加了多选列和对应的回调函数。
问题描述
当保存运行代码后,表格并没有渲染出多选列,并且多选列别序号列给代替了。如图渲染错误表格:
多选列 | 序号 | 业务字段名 |
1 | 1 | data1 |
2 | 2 | data2 |
分析问题
检查了代码,参照了组件文档发现并没有问题,捋了捋逻辑也没有问题,最后只能网上找答案,搜寻一圈也没有找到跟我类似的业务场景和问题。
思考尝试
想着是不是这个v-if指令的问题,导致表格渲染错误的,于是就尝试将v-if更换成了v-show,果然更换之后表格正常渲染。
现在有必要聊一聊v-if和v-show的区别了。
- v-if能够控制是否生成vnode,也就间接控制了是否生成对应的dom。当v-if为true时,会生成对应的vnode,并生成对应的dom元素;当其为false时,不会生成对应的vnode,自然不会生成任何的dom元素。
- v-show始终会生成vnode,也就间接导致了始终生成dom。它只是控制dom的display属性,当v-show为true时,不做任何处理;当其为false时,生成的dom的display属性为none。
- 使用v-if可以有效的减少树的节点和渲染量,但也会导致树的不稳定;而使用v-show可以保持树的稳定,但不能减少树的节点和渲染量。
- 因此,在实际开发中,显示状态变化频繁的情况下应该使用v-show,以保持树的稳定;显示状态变化较少时应该使用v-if,以减少树的节点和渲染量。
所以出现以上问题的原因基本就能定位是:
- 由于tab组件本来就是频繁切换的组件,使用v-if的话就会使dom树不稳定,从而造成渲染错误的。
- el-tabs组件内部应该也是使用v-show来控制的(没有看源码,我猜的),由于v-if和v-show是互斥的,即同一个元素上同时使用v-if和v-show时,v-if的优先级更高,会覆盖v-show的效果。因此,如果v-if的条件为假,元素将不会被渲染到DOM中,无论v-show的条件是真还是假。(因此如果你将业务内容放到el-tabs组件的子标签内的换,应该不会出现该问题。)
总结
以上只是一个开发过程中遇到的小问题,在这里总结记录一下,如果针对问题有不同的见解欢迎评论留言。也希望能够帮到遇到同样问题的小伙伴。