gk-shi/v3-waterfall

替换数据源或者删减数据源中的数据(`:list="data"`)后渲染不正确

Yefancy opened this issue · 7 comments

Behavior:
image

Des:
如题,当以下code的watch中 filters更新后,会触发data重写this.data=[],data时:list"data"的数据源。然后有概率造成渲染错误。
已经尝试过在data更新后调用this.$refs.v3w.reRender(); 但是依然存在这个问题

Component:

<script setup>

</script>

<template>
<div class="container">
  <div class="waterfall-container">
    <v3-waterfall ref="v3w" class="waterfall" :list="data" srcKey="cover" :gap="10" :colWidth="itemWidth"
                  :distanceToScroll="200"
                  scrollBodySelector=".waterfall-container"
                  :isMounted="isMounted"
                  :isLoading="loading"
                  @scrollReachBottom="loadMore"
    >
      <template v-slot:default="slotProp">
        <div
            class="cell-item"
            @click="() => handleClick(slotProp.item.id)"
        >
          <img class="img" :src="slotProp.item.cover" alt="加载错误" />
        </div>
      </template>
    </v3-waterfall>
  </div>

</div>
</template>

<script>
export default {
  props: {
    filters: Object,
    isMounted: Boolean
  },
  data() {
    return {
      col: 3,
      data: [],
      offset: 0,
      size: 20,
      loading: false,
      isShow: true,
    };
  },
  methods: {
    loadMore() {
      this.offset += this.size;
      console.log("loadMore")
      this.loadImages();
    },
    handleClick(index) {
      console.log(index);
    },
    loadImages() {
      if (this.filters && !this.loading) {
        this.loading = true;
        let filters = [];
        for (let dim in this.filters) {
          filters.push({
            dimension: dim,
            minSimilarity: this.filters[dim][0],
            maxSimilarity: this.filters[dim][1]
          })
        }
        this.$http.post('inquiry_images_by_dimension', {
          filters: filters,
          offset: this.offset,
          size: this.size
        }).then(res => {
          res.data.forEach(item => {
            item.cover = this.getImageSrc(item);
          })
          this.data = this.data.concat(res.data);
          this.$refs.v3w.reRender();
          this.loading = false;
          this.isShow = true;
        })
      }
    },
    getImageSrc(item) {
      return this.$http.defaults.baseURL + `/image/${item.imagePath}/${item.imageName}`;
    }
  },
  computed: {
    itemWidth() {
      return (document.documentElement.clientWidth * 0.4 - 10 * (this.col - 1) - 10 - 10 * 2) / this.col;
    }
  },
  mounted() {
    if (this.loading) return;
    this.offset = 0;
    this.data = []
    console.log("mounted")
    this.loadImages();
  },
  watch: {
    filters: {
      handler() {
        if (this.loading) return;
        this.offset = 0;
        this.data = []
        console.log("watch")
        this.loadImages();
      },
      "deep": true
    }
  }
}
</script>

<style scoped>
.container {
  width: 40%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  border-radius: 20px;
  box-sizing: border-box;
  ::-webkit-scrollbar {
    width: 4px;
  }
}

.waterfall-container {
  width: 100%;
  height: 100%;
  padding: 10px;
  overflow-y: scroll; /* 一定要制定父元素超出滚动 */
}

.img {
  width: 100%;
  height: auto;
  display: block;
}

.cell-item {
  width: 100%;
  background: #ffffff;
  border: 2px solid #F0F0F0;
  border-radius: 12px 12px 12px 12px;
  overflow: hidden;
  box-sizing: border-box;
  margin-bottom: 10px;
}
</style>
Cannot read properties of undefined (reading 'querySelector')
TypeError: Cannot read properties of undefined (reading 'querySelector')
    at layoutHandle (webpack-internal:///./node_modules/v3-waterfall/dist/v3-waterfall.es.js:138:30)
    at eval (webpack-internal:///./node_modules/v3-waterfall/dist/v3-waterfall.es.js:376:61)
    at eval (webpack-internal:///./node_modules/v3-waterfall/dist/v3-waterfall.es.js:56:24)

当触发上面渲染错误后,通过滚轮尝试加载更多数据时还会触发这个报错

通过

this.data.splice(0, this.data.length);
// or
this.data.length = 0

来清空数组来更新数据源数组可以明显减少触发该问题的几率,但是仍然有概率触发。

如何正确删减list数据源中的数据呢?

@Yefancy

  1. 目前版本list不建议进行删减或者更改以渲染元素中会影响渲染高度的属性,如果确实要改,就需要通过reRender来触发重新排版。至于重新赋值,我试了是 ok 的,我在 code sandbox 里创了个例子,你可以试试看:
    代码:https://codesandbox.io/s/fervent-jones-j53tg5?file=/src/App.vue
    展示:https://j53tg5.csb.app/
image

2.至于说触发重渲染后的控制台报错 Cannot read properties of undefined (reading 'querySelector') ...,我在上面示例代码中,快速连续点击【重排或删除第2项重排】时会触发这个问题,以及偶尔出现你最上面图片中出现的布局部分有错乱,这个问题是因为内部用了一些 微任务、宏任务,然后碰上快速重置时 dom 有时候并没有准备好的问题,因为目前内部没有实现该情况的处理,建议可以外部对相关操作进行一些防抖或节流操作。

tbh,我对vue和web开发并不深刻了解,不过我意识到抖动是触发该问题的原因之一。其实昨天issue后我尝试添加防抖,的确几乎不再遇到这个问题(任然有极低的概率遇到,因为我不能确定dom什么时候渲染结束,如果此时更新data,任然会触发这个问题)。

感谢你的帮助

作为插件的开发者很高兴和感谢有人使用并帮助我发现里面存在的一些问题😆。因为这个库是在 vue3.0 刚出不久的时候开发的,当时的设计存在一些缺陷,现在正在重新设计某些过程,到时候一些问题都会在内部默认处理掉了

一个小建议,我觉得可以提供两种布局模式:

  1. 当前的根据img动态计算高度的模式 (但目前只能支持一个img)
  2. 用户提供高度(类似于 https://github.com/lhlyu/vue-virtual-waterfall ),自动布局的性能和可靠性都得到保证