gk-shi / v3-waterfall

a waterfall plugin for Vue 3. 一个 vue 3 的自适应瀑布流组件。

Home Page:https://gk-shi.github.io/v3-waterfall/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

元素不定高 bottomGap设置无法设置正常的margin,导致上下卡片重叠严重

wmhh1129 opened this issue · comments

环境是vue3 + vite

找到原因了,是因为我的srcKey设置错了,但是我设置完毕后,间隙又会变得特别宽,哪怕我不设置任何bottomGap
image
@gk-shi 作者大大

还有一个问题,当我在多Tab页面切换的时候,图片渲染得非常慢,我猜测是在等待图片的加载,阻塞了整个渲染进程
image

可以提供一个 codesand box 链接,或者一个复现最小仓库的话,我可以帮忙看一下,这里提供一下之前 issue 的情况以供参考:
1.每个元素间的过大空余问题可能是: #8
2.需要使用 tab 栏切换时建议:页面中只使用一个v3-waterfall,使用一个数组作为数据来源,tab 仅做一个展示切换(文档中个人博客里就是这么做的):

<el-tabs>
  <el-tab-pane>1</el-tab-pane>
  <el-tab-pane>2</el-tab-pane>
</el-tabs>

<v3-waterfall :list="list"></v3-waterfall>

监听 tab 的切换,然后更新 list 数组的内容,当然,isOver 字段也需要进行对应变更。

当前next分支正在对1.x重写,后面会提供方法交于用户控制

1、间距过大的问题,我排查了一下我的样式,我给卡片有一个min-height:100px,可能跟你的逻辑冲突了。
2、另外,我分别测试了内容嵌套在tab内,以及在外部的两种方式,我感觉渲染的速度差不了很多,看起来像是要等图片onload完才会渲染?我还没有认真去看源码(这块有打算做优化吗)
3、除了目前的动画,能否支持fade-in,或者说有配置可以关闭动画效果?

再次感谢作者认真回复🌹 @gk-shi

1、间距过大的问题,我排查了一下我的样式,我给卡片有一个min-height:100px,可能跟你的逻辑冲突了。 2、另外,我分别测试了内容嵌套在tab内,以及在外部的两种方式,我感觉渲染的速度差不了很多,看起来像是要等图片onload完才会渲染?我还没有认真去看源码(这块有打算做优化吗) 3、除了目前的动画,能否支持fade-in,或者说有配置可以关闭动画效果?

再次感谢作者认真回复🌹 @gk-shi

A1: 目前版本由于设计问题造成该问题,下版本不会有了

A2: 你想的是对的,因为定位布局需要知道每个元素的高度,因此我需要先加载完图片才能进行高度计算。下版本提供两个方案可选:1.使用内部计算高度方案,此方案需要预加载图片后才能进行高度计算,目前没想到有更好的方案;2.用户提供高度计算函数,这种方案是满足用户能够通过接口数据就快速知道元素高度,不需要加载图片

A3: 目前版本的动画是我内置写死了这种,没有暴露更改或关闭,但是也有降级方案可以实现:

// 注意是在文件中多加了一个全局的 style 标签,不能带 scoped
<style>
.waterfall-item {
  // 清除或自定义动画
  animation: none;
}
</style>

<style scoped>
  // 此处是当前文件其他的隔离样式内容
</style>

1、小问题,可以不写最小高度
2、这个问题比较严重,我目前用pageSize = 5,每次只加载五个图,感觉都得等一会儿
3、也是小问题,我样式覆盖就可以
4、还有一个问题,tab切换的时候,图片又会重新加载多一次,这个应该得有个优化策略,要不然吃不消

另外我想问问,如果我这边可以提供图片高度,最近会有新版本迭代吗

1、小问题,可以不写最小高度 2、这个问题比较严重,我目前用pageSize = 5,每次只加载五个图,感觉都得等一会儿 3、也是小问题,我样式覆盖就可以 4、还有一个问题,tab切换的时候,图片又会重新加载多一次,这个应该得有个优化策略,要不然吃不消

另外我想问问,如果我这边可以提供图片高度,最近会有新版本迭代吗

慢主要是出在首次加载图片计算高度的时候,切换 tab 时如果是切到之前加载过的图片那边,从缓存读取速度会快很多。

最近可能不会为了这个情况单独更新一版,我是打算最迟在清明节左右提供一个 2.0 的 beta 版本,到时候会提供用户可以自己计算高度的 hook 以及关闭默认动画等

2.0的beta版本,如果用户可以提供图片的高度,可以提高渲染速度吗

2.0的beta版本,如果用户可以提供图片的高度,可以提高渲染速度吗

单纯的提供图片高度没用,一个元素的高度决定取决于两个部分,1:文字类、样式类影响高度,2:图片类受网络请求加载影响。
目前动态计算高度的步骤为:在页面看不见的地方渲染出该元素,等待图片加载完成后,计算整体高度。

第一部分高度在渲染时就能同步获取到实际高度,第二部分则需要看图片大小、网络带宽速度了。

由于元素块内容是用户通过 slot 自定义的,我不知道他用了多少张图片、每个图片是按照元素宽度等比缩放,还是设置死了宽高?因此我没办法说内部拿到用户给的图片宽高完成高度计算。(当前 1.x 的版本就是我默认用户就使用一张图片,并且这张图片的展示宽度就是元素块的宽度,高度进行等比缩放;但 2.0 开始我是支持了一个元素块的多张图片的)

回到你提的问题,如果你的需求正好是我 1.x 版本所描述的这种展示方案,那在 2.0 版本是可以自己提供高度计算方法提高渲染速度的。到时候我会提供相应的示例以供参考,现在我能大概讲讲思路:

  1. 根据提供的 slot、item 数据、元素块 width,使用 render 函数渲染出元素块
    2.获取 img 标签进行隐藏,避免 img 的默认高度影响计算
    3.通过 offsetHeight 获取元素高度(除图片高度)
    4.因为已知图片原 宽x高,当前知道元素 width ,等比缩放获取图片高度 imgHeight
    5.返回该元素高度 offsetHeight + imgHeight
    6.删除该渲染元素块

这样就能不需要图片加载完就能直接获取元素高度了。

因为已知图片原 宽x高,当前知道元素 width ,等比缩放获取图片高度 imgHeight

关于这一点,如果图片不加载完,通过怎么来知道图片比例呢。

我看了vue-waterfall2的源码,其实里面的问题也有点多,但是有一点可以借鉴,就是无须等全部图片出来才渲染,可以一张完了就append一张,然后不停的给比较矮的那一列去加元素就可以了?

另外我看了一下源码,监听数据变化这一块
image
只要是数组第一个变了,就会重新进行图片预加载,这样其实对于多Tab页面就非常不友好了,包括你的blog页面也是如此

1.因为有的人在接口返回数据时,就会同步在接口中返回图片的宽x高,这时候加载图片再进行计算就显得多余了。

2.关于元素单个依次渲染的问题,其实之前有考虑过,只是最后做了取舍而已。
在做虚拟列表的时候,因为我已经记录了每个元素的位置信息,其实只需要获取到滚动位置,然后循环一遍就能判断出当前位置要展示哪些(当然这里可以优化不需要走完一遍完整的循环)。
如果我把本次新的元素都加载完,那么我的循环、元素的重绘、重排一次就好了,单个依次渲染就需要走多遍这个流程。

3.在当时做这个瀑布流的时候,我一直认为瀑布流是一个增量更新的过程,已经渲染过的元素可以认为它已经“死”了,所以如果这个列表的第一个元素都发生了变化,那么我就认为这是一个新的瀑布流,重新加载计算显然就正常了。
至于你说的重新进行图片预加载:
1711071478644
1711071478700
因为浏览器默认是会缓存的,所以打开控制台时把这个禁止缓存去掉(因为控制台用于调试,为了防止缓存影响,浏览器在打开控制台时会默认成禁止缓存),你再切换各个 tab ,其实图片内容还在内存中时,甚至都不会发起图片加载的新请求,即使内存没了,新的预加载也是从缓存中加载的,花费的时间也是很少的。当然,如果你切换新的 tab 加载了新的图片,肯定要等待的。

本质上,我认为瀑布流适用的场景是作为信息概览展示的,如果一个元素卡对应的是博文的封面+内容,那么对应到瀑布流中的元素卡,它就是缩略图+文章梗概。所以,其实我不太建议在瀑布流中使用高清原图的。

嗯,我非常理解你的设计初衷的单列表无限滚动,卡片是增量式的存在,这样的话只有首屏的渲染,接下来渲染不会太大,目前的设计以及足够了。
另外即使关闭了disable cache,切换tab的时候依然会重新onload图片,你可以在你的博客页面测试一下,我已经试过了,而且因为此前我的业务应用上了你的库,在手机上表现得也非常明显,切回之前的tab的时候,需要加载很久才会展示。
只能说如果要兼容页面切换,保留前一份已经渲染过的列表的话,watch函数里面的判断就得加变量去适配了。

嗯,我非常理解你的设计初衷的单列表无限滚动,卡片是增量式的存在,这样的话只有首屏的渲染,接下来渲染不会太大,目前的设计以及足够了。 另外即使关闭了disable cache,切换tab的时候依然会重新onload图片,你可以在你的博客页面测试一下,我已经试过了,而且因为此前我的业务应用上了你的库,在手机上表现得也非常明显,切回之前的tab的时候,需要加载很久才会展示。 只能说如果要兼容页面切换,保留前一份已经渲染过的列表的话,watch函数里面的判断就得加变量去适配了。

你这里说的切回之前的 tab ,我想问一下是不是下面我时候的情形:

  1. 在 tab1 的时候,往下加载了比如 60 项
  2. 切换到 tab2 去,你把 tab1 的 60 项都存下来了
  3. 重新切回 tab1 ,你取出自己存的 60 项,一次性替换 list

如果是这么一个过程,那么在 tab1 时存的东西越多,切换回去的时候的确会更耗时,因为相当于一次性计算了 60 项。

另外即使关闭了disable cache,切换tab的时候依然会重新onload图片

针对这个的话,我去试了看,只要我第一次加载过的图片,后面切换过来的时候 onload 都是走的 disk cache 啊,速度比首次加载的时候快很多。如果你那边能截图的话可以麻烦截个图给我看看,我排查一下。

是的,跟你描述得情景是一样的。
对,走的是disk cache,但还是慢,也许也是因为多个串起来而且需要计算。

你可以看一下我们的业务场景如同 https://h5.aomiapp.com/discover/#/ ,这个旧业务用的是vue waterfall v1.9.6,是旧版本,体验就挺好的,而且来回切不需要重新加载,我们新项目已经用vue3 + vite,虽然说他们出了vue waterfall2兼容了vite打包,但我看了一下源码,一堆问题,连loadmore的逻辑都是错的,而且库也没有维护了,就弃了

79d95a43-08bf-45cb-a826-14fa0166808f.0.132aa398-fd04-488d-a317-6e22ac881ba5.mp4

这是我用你上面提供的业务场景的例子中的接口,配合v3-waterfall@1.3.3做的,其实图片尺寸做了控制的话,速度也不会到不能接受。我也是可以实现切换到前一个加载的 tab 不需要重新渲染图片的,就是渲染了多个 v3-waterfall 组件(我看了你给的例子中也是渲染了多个组容器,在 tabs 中会display: none非当前 tab)

视频的效果是v1.3.3吗,还是改良版,图片尺寸做了控制,具体指的是?

代码在这里:https://codesandbox.io/p/devbox/my-vue3-app-demo-pqkr2t?file=%2Fsrc%2FApp.vue%3A9%2C1

我肯定是没有动我插件的源码的,我这里只是做了个简单的演示效果

嗯嗯,我也重新试了,确实是可以的,那天不知道代码哪里有问题,导致会无限的加载页数,而且我这边vant tab还用了swipeable属性,手势滑过去第二个分类会白屏,sandbox里面加个swipeable也可复现。

另外我想知道next版本,会有哪些优化,我可能会蹲一波然后用上。

btw:已经star了,作者回复很用心🌹

代码在这里:https://codesandbox.io/p/devbox/my-vue3-app-demo-pqkr2t?file=%2Fsrc%2FApp.vue%3A9%2C1

我肯定是没有动我插件的源码的,我这里只是做了个简单的演示效果

还是这个代码地址,目前加上 swipeable 是可以的了。
image
之前不行是因为我偷了个懒,取巧使用了我内部的一个校验底部锚点是否滚出屏幕,如果没有,我会再触发一次 loadMore...
实际上还是如截图上第1点说的,首次加载还是由用户自己来控制,当时可能也是为了规避一些问题~

虽然我当时在展示上做了些移动端的想法,但是一些移动端特有的事件啥的我都没考虑过,所以有些东西可能还是要自己来控制😂

1、关于swipeable,还是有点问题,我这边有个需求,会根据另外的配置来决定当前激活哪个tab,假设初始我激活是第二个tab的时候,数据依然渲染到了 list.value[0] 底下,不懂哪里出了问题,所以我暂时放弃这个属性了。
2、我还观察到一个细微的点,我们有个埋点的逻辑,埋点的逻辑是通过指令挂在dom上,监听dom的生命周期配合IntersectionObserver来观察的,下拉刷新的时候,因为数组会先清空,再concat第一页的值,从而waterfall的dom会重绘,导致二次曝光,v-for渲染的普通列表,list = [], 再给list赋值,dom是不会重新走生命周期的

1、关于swipeable,还是有点问题,我这边有个需求,会根据另外的配置来决定当前激活哪个tab,假设初始我激活是第二个tab的时候,数据依然渲染到了 list.value[0] 底下,不懂哪里出了问题,所以我暂时放弃这个属性了。 2、我还观察到一个细微的点,我们有个埋点的逻辑,埋点的逻辑是通过指令挂在dom上,监听dom的生命周期配合IntersectionObserver来观察的,下拉刷新的时候,因为数组会先清空,再concat第一页的值,从而waterfall的dom会重绘,导致二次曝光,v-for渲染的普通列表,list = [], 再给list赋值,dom是不会重新走生命周期的

第1点问题是属于业务问题了,我大概想了下思路,其实也是可以通过增加业务代码处理掉的。第2点目前2.0.0-beta.1新增insertBefore方法支持往头部插入新的元素组,之前的元素卡片key不会发生变化,只改变了位置样式,应该不会重新触发指令生命周期了。