阅读 353

van-tabs 组件不响应了?

问题阐述

这个问题,遇到的真的是很奇怪的。

事情是这样的:这其实是我的一个项目需求。点击导航右侧更多按钮,出现对话框,可以拖拽导航列表,更换导航栏顺序。看着是不难的,但是当拖拽完成之后,你就会发现页面上的导航栏并未发生任何变化。

image.png

关于项目

image.png

App 父组件

  <van-tabs     v-model="active"     swipe-threshold="4"     class="tab"     title-active-color="#3693FF"     color="#3693FF"     title-inactive-color="#4A4A4A"     @click-tab="chooseNav"   >     <van-tab v-for="item in navList" :key="item.name" :name="item.name" :title="item.title">       <component :is="item.component" class="tabPanel"></component>     </van-tab>   </van-tabs> </div> <sort-nav   :isSortNav="isSortNav"   :list="navListClone"   @newList="newList"   @noSortshow="noSortshow" ></sort-nav> // 在点击右上角触发弹框子组件时,给子组件传入`isSortNav`(控制弹框显示)、`navListClone`(拖拽列表绑定数据) 复制代码

子组件

<van-popup   v-model="isSortNav"   round   position="bottom"   :style="{ height: '70%' }"   :overlay-style="{ opacity: 0.5 }"   :close-on-click-overlay="false"   @click-overlay="noSortNav" >   <div class="sortContent">       <div class="packUp">         <img src="@/assets/arrowDown.png" alt="" />       </div>       <div class="dataTittle">         <div>全部数据项</div>         <div class="rightTittle">长按右侧拖拽可排序</div>       </div>       <div class="dataOption">         <vue-draggable           :list="list"           class="list-group"           ghost-class="ghost"           @start="dragging = true"           @end="dragging = false"         >           <div v-for="item in list" :key="item.name" class="list-group-item">             <div class="list-item-left">               <div class="list-item-icon">                 <img :src="require('@/assets/drag/' + item.name + '.png')" alt="" />               </div>               <div class="list-item-title">                 {{ item.title }}               </div>               <div class="list-item-annotation">                 {{ item.annotation }}               </div>             </div>             <div class="list-item-drag">               <van-icon name="wap-nav" />             </div>           </div>         </vue-draggable>       </div>   </div> </van-popup> 复制代码

// 点击退出弹框,给父组件传入最新排序的数据 noSortNav() {   this.$emit('noSortshow', !this.isSortNav)   this.$emit('newList', this.list) }, 复制代码

解决方案

该项目基于vue2 + vant + vuedraggable。

排查

组件通信

首先确保自己组件之间的通信是否成功,通过打印或者断点方式,查看父子组件接收和传入的参数:

image.png 检查后发现并没有任何问题。

tab数据绑定

接下来,检查tab导航数据是否绑定成功。 在nav导航上添加数据,查看导航绑定的数据是否成功被拖拽所更改。如下图:

86ffm-kgm5y.gif

可以看出数据是发生了变化,但是导航tab并未发生变化。

那么说明我的组件和拖拽使用的没有问题。那么可能就是vant tabs导航组件渲染的问题。

解决

既然是组件没有刷新绑定新的数据。那么我们很快就会想到,现将绑定的数据置空,然后再去赋值。 emmm。。。

实践证明该方法不可行!

那么我们可以通过强制tabs组件刷新,来重新渲染更新后的组件数据。

组件强制渲染有很多种方法:

$forceUpdate

迫使 Vue 实例重新渲染。注意它仅仅影响实例本身插入插槽内容的子组件,而不是所有子组件。

在上述情况中,使用$forceUpdate其实是无效的。因为重新渲染的是本身和插入插槽内容的子组件。而tabs组件是vant中已经封装好的,并不属于我们本身的插槽。

渲染失败!

改变key

我们看过vue内部的应该都知道,vue在重新渲染的是时候,是去对比它自身的key是否发生变化。那这样我们就会想到,给tabs组件绑定一个动态的key属性,在拖拽完成之后去改变这个key的值。

再试一下:

// van-tabs 组件绑定key为index,在父组件拿到子组件返回之后手动更新该组件的key值。 newList(val) {   this.navList = val   this.index++ }, 复制代码

8487d-6ud5m.gif

ok,这个方法可行!

改变绑定数据

一开始赋值不行,那我等dom渲染完成之后呢?
既然想到要改变key,那么我们在拖拽完成之后,加一个nextTick是不是也可行呢? 在拖拽完成之后,置空绑定数据,再添加一个nextTick,在其内部去给绑定的数据重新赋值。

newList(val) {   this.navList = []   this.$nextTick(() => {     this.navList = val     console.log(this.active)   }) } 复制代码

klb3u-56crd.gif

ok,这方法也可行!

tab循环绑定index为key

需要key的改变的话,那我是不是也可以通过索引去匹配标签页呢? 当数据发生变化

<van-tabs   v-model="active"   swipe-threshold="4"   class="tab"   title-active-color="#3693FF"   color="#3693FF"   title-inactive-color="#4A4A4A"   @click-tab="chooseNav" >   <van-tab     v-for="(item, index) in navList"     :key="index"     :name="item.name"     :title="item.title"   >     <component :is="item.component" class="tabPanel"></component>   </van-tab> </van-tabs> <script> newList(val) {    this.navList = val  }, </script> 复制代码

c8mg9-z627h.gif

ok,这方法也可行!

总结

van-tab组件对于json数组的导航数据,在内部,用唯一键标识(item.name)key值,其实在dom-diff新老节点作比较的时候,是默认其key属性是一样的。会进行头头、尾尾、头尾、尾头的比较,key值一样的时候会进行复用,导致导航栏不存在更新渲染。


作者:ClyingDeng
链接:https://juejin.cn/post/7028202465086423053

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