Vant: [Bug Report] van-tabs组件标签乱序

Created on 16 Apr 2020  ·  16Comments  ·  Source: youzan/vant

设备 / 浏览器

微信浏览器windows版、Android某些机型(如小米)

Vant 版本

2.6.1

Vue 版本

2.6.11

重现链接

https://keyike.ltd/huoke-wx/test-van-tabs-disorder

描述问题

van-tabs组件中的van-tab子组件数量过多时,在android某些机型(如小米)和win10微信电脑版中,标签的顺序会变乱。

🐞 bug 💩 browser quirks

Most helpful comment

已发布 2.6.3 版本,可以试一下

All 16 comments

变乱具体是什么效果,有截图不

界面截图:

微信截图_20200416163229

暂时没复现,近期会找台手机复现试下

win10的微信浏览器很容易重现。

  • 在Chrome53上有重现;

    Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1268.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 wxwork/3.0.16 (MicroMessenger/6.2) WindowsWechat

  • 乱序后的顺序和楼主一样;

  • 在且仅在tab数量在11个(含)以上的情况下复现;
    这个值,和浏览器对应的v8中的 sort() 选择插入排序和快排的临界点,是一样的;
    但是在源码里好像没有用到sort -,-!

DOM 节点也是乱序的嘛?

DOM 节点也是乱序的嘛?

是的

那就有点儿诡异了。。

@chenjiahan
在低版本的v8中,Array.prototype.sort 对于 Array.lenght > 10 使用的是快速排序,这意味着 sort( () => 0)可能会交换子项位置;

/src/utils/vnodes.ts

// sort children instances by vnodes order
export function sortChildren(children: VueInstance[], parent: VueInstance) {
  // null on SSR
  if (!parent._vnode) {
    return;
  }

  const vnodes = flattenVNodes(parent._vnode.children!);
  children.forEach(i => {
    console.log(vnodes.indexOf(i.$vnode)); // output: -1
  });
  children.sort((a, b) => vnodes.indexOf(a.$vnode) - vnodes.indexOf(b.$vnode));
}

不过这里本来就预期会交换元素位置的

这个函数看不懂:
indexOf接受第一个参数是string,这里的a.$vnode类型是VNode,所以返回值恒为-1;
就算sort不错乱,children.sort()后原数组没有变换,相当于什么事也没干。

我的锅,这里不该用 _vnode 的,可以改成下面的写法试下

image

另外这个函数的作用是解决动态插入节点的顺序问题,比如下面的情况:

<template>
  <van-tabs v-model="active">
    <van-tab title="1">1</van-tab>
    <div v-if="insert">
      <van-tab title="2">2</van-tab>
    </div>
    <van-tab title="3">3</van-tab>
  </van-tabs>
</template>

<script>
export default {
  data() {
    setTimeout(() => {
      this.insert = true;
    }, 1000);
    return {
      insert: false,
      active: 0
    };
  }
};
</script>

换了个写法: #6100

已发布 2.6.3 版本,可以试一下

问题解决,感谢各位大神。

Was this page helpful?
0 / 5 - 0 ratings