阅读 140

表格表头拖拽后,串行了,原来是“key”

前言

Vue中key的作用是什么?这个问题大家应该都不陌生。当然,我也接触过,但是还停留在接触这个阶段,当真正遇到问题的时候,差点栽跟头。

我遇到的问题

近几天,有一个表格表头拖拽的需求,如图所示,右侧自定义列的字段是表格中正展示的字段,右侧自定义列中的字段可拖拽,同时在左侧的表格中同步拖拽后的顺序。自身在实践的过程中发现,右侧拖拽后,左侧表格中的显示有问题,比如标题和创建时间位置互换,但是表格中渲染出来的第一列表头是标题,第二列还是标题,下面对应的内容是对的,那这个问题的原因是什么呢?先来看看我的代码实现吧。

image.png

表格拖拽代码

表格代码:

<div class="table-div"> <elable   ref="table"   v-loading="loading"   :data="data"   v-bind="tableProps"   style="width: 100%;"   :row-class-name="rowClassName"   @header-dragend="handleDrag"   @row-dblclick="dblclickRow"   @sort-change="handleSortChange"   @selection-change="onSelectionChange" >   <template v-if="columns.length > 0">     <el-table-column       v-for="(column, index) in columns"       :key="index       v-bind="column"       :min-width="column.minWidth || 140"       :resizable="true"       :show-overflow-tooltip="true"     />   </template>   <slot v-else /> </el-table> </div> 复制代码

自定义列拖拽组件封装代码:

<div class="display-field-wrapper">     <el-popover       ref="display-field-popover"       placement="bottom"       width="216"       popper-class="custom-field-popover"       trigger="click"     >       <div class="display-field__popover-panel">         <div class="screening-box">           <el-select             v-if="showGroup"             v-model="typeValue"             class="display-field__search"             placeholder="全部字段类型"           >             <el-option               v-for="item in typeOptions"               :key="item.value"               :label="item.label"               :value="item.value"             />           </el-select>         </div>         <div class="display-field__title">           <span class="select-title">{{ enableLabel }}</span>           <span class="select-counts">{{ fieldCheckedList.length +'/'+ fieldLen }}</span>         </div>         <div class="display-field__checked-list">           <draggable             v-model="enableFieldsFilter"             :draggable="draggableClass"             @sort="onSort"           >             <div               v-for="item in enableFieldsFilter"               :key="item.prop"               class="display-field__check-item"               :class="{ 'display-field__draggable-item': item.can_cancel }"             >               <el-checkbox                 v-model="fieldCheckedList"                 :label="item.label"                 :disabled="!item.can_cancel"                 @change="handleCheck(item, -1)"               />             </div>           </draggable>         </div>         <div class="display-field__title">           <span class="select-title">{{ notEnableLabel }}</span>           <span class="select-counts">{{ (fieldLen - fieldCheckedList.length) +'/'+ fieldLen }}</span>         </div>         <div class="display-field__unchecked-list">           <div             v-for="item in notEnableFieldsFilter"             :key="item.prop"             class="display-field__check-item"           >             <el-checkbox               v-model="fieldCheckedList"               :label="item.label"               :disabled="!item.can_cancel"               @change="handleCheck(item, 1)"             />           </div>         </div>       </div>     </el-popver>   </div> 复制代码

其实当时我在排查的时候,首先在组件中排查,以为拖拽有问题,但是实际上,内容是对的,只是表头有问题,这才想起之前的一个知识点,说实话,这个点早就知道,但是自己也确实没遇到过类似问题,所以也没在意。一般我在写for循环的时候,都会像上述代码中那样写,key值就写个index,一直没遇到过问题。哈哈。

key的真实作用

key是虚拟DOM对象的标识,当数据发生变化时,vue会根据新数据生成新的虚拟DOM,随后VUe进行新虚拟DOM与旧虚拟DOM的差异比较。比较规则是什么呢?

(1)旧虚拟DOM中找到了与新虚拟DOM相同的key: 若虚拟DOM中内容没变,直接使用之前的真实DOM;若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

(2)旧虚拟DOM中未找到与新虚拟DOM相同的key,则创建新的真实DOM,随后渲染到页面中。

问题解决

那上面我的问题就应该有答案了。我是用index值作为的key,那当我拖拽之后,在进行对比的过程中,发现索引值没变,那干脆内容也不变了。后来我将key值加index的同时,还加上了一个会变化的字段,那就是列的定义字段,这样就能保证在进行diff算法的过程中,会有变化啦。

总结

 伪原创工具 SEO网站优化  https://www.237it.com/ 

在日常开发中个,尽量选择每条数据的唯一标识作为key,比如id等,避免出现类似问题;如果不对数据的逆序添加、删除等破坏顺序的操作,仅仅用于列表渲染,其实使用index作为key是没有问题的。

Happy Ending.


作者:Delicia_Lani
链接:https://juejin.cn/post/7035450586417856520

文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐