小程序瀑布流的实践
时间:2021-12-03 来源:互联网 编辑:宝哥软件园 浏览:次
最近在工作中,我在微信小程序中实现了瀑布流列表(左右栏、动态图文),最终效果还不错,所以在这里记录下来,仅供有需要的人参考。
最终效果:
另外,要做瀑布流,最好知道图片的高度,这是界面发送来提前占用空间的。否则,即使是原生应用也会因为画面闪烁而导致用户体验不佳。在小程序中,没有原生app的流式布局控件,所以如果不知道图片的宽度和高度,只能先缩小每页的page_size,然后在加载图片后再计算插入位置(这对于产品来说可能是一个无法接受的漫长过程)。
ding: 0px; font-size: 18px; border: 0px; font-weight: normal; font-family: "Helvetica Neue", Helvetica, Tahoma, Arial, STXihei, "Microsoft YaHei", 微软雅黑, sans-serif; line-height: 1.6em; color: rgb(51, 51, 51); text-rendering: optimizelegibility; text-indent: 1em; background-color: rgb(254, 254, 254);">尝试过的小程序瀑布流实现方式
1.左右两列判断奇偶性渲染
//demo.jsPage({ data:{ renderLists:[] }, fetchData(){ request(url,params).then(res=>{ const PreData=this.data.renderLists this.setData({ renderLists:PreData.concat(res) }) }) }})//demo.wxml<view class="waterfall"> <view class="waterfall__left"> <your-compoent wx:for="{{renderLists}}" wx:key="id" wx:if="{{index % 2 === 0}}" /> </view> <view class="waterfall__right"> <your-compoent wx:for="{{renderLists}}" wx:key="id" wx:if="{{index % 2 === 1}}" /> </view></view>
或许京东购物小程序-首页就是这样做的?(不确定)
2.绝对定位
这个方式可能就是目前pc端的实现方式,原理都一样。但是在小程序中,有以下几个需要解决的问题
- 如果列表是动态图文,即使知道图片宽高,如何获取文字内容区域的高度?
- 安卓下实验过会出现白屏,卡顿等性能问题(这个问题导致直接放弃了这个做法)
3.左右两列计算插入渲染
//demo.jsPage({ data:{ leftLists:[], rightLists:[] }, onLoad(){ this.leftHeight=0 this.rightHeight=0 }, fetchData(){ request(url,params).then(res=>{ this.generate(res) }) }, generate(list){ let leftList=[],rightList=[] list.map(async (item)=>{ //每个item的高度=图片宽高+内容区域 const itemHeight=getImageHeight(item)+getContentHeight(item)+gap this.leftHeight>this.rightHeight?rightList.push[item]:leftList.push(item) }) this.render({leftList,rightList}) }, getImageHeight(){ //如果知道图片宽高,就return item.height //如果不知道,wx.getImageInfo(需要配合域名)或者通过display:"node" image 然后 bindload。 }, getContentHeight(){ //文字内容区域高度固定,直接返回 //不固定,做数据映射,例如10个字一行,行高按照设计稿,做rpxToPx返回 }, render(params){ const {leftList,rightList}=params const preLeft=this.data.leftList; const preRight=this.data.rightList this.setData({ leftList:preLeft.concat(leftList), rightList:preRight.concat(rightList) },()=>{ const query = this.createSelectorQuery(); query.select('.wrapper__left').boundingClientRect(); query.select('.wrapper__right').boundingClientRect(); query.exec((res) => { this.leftHeight = res[0].height; this.rightHeight = res[1].height; }); }) }})//demo.wxml<view class="waterfall"> <view class="waterfall__left"> <your-compoent wx:for="{{leftLists}}" wx:key="id" /> </view> <view class="waterfall__right"> <your-compoent wx:for="{{rightLists}}" wx:key="id" /> </view></view>
注意下面的操作都必须是一个同步获取的过程,需要异步获取的都要async await,如果需要异步获取的数据多,例如图片,那就是一个耗时操作可能有小概率会影响我们的计算,这个问题是存在的且可以接受的createSelectorQuery
可以看下小程序附近的餐厅
,效果很好,他的图片宽高是服务器返回的,文字内容区域是固定的(标题只有几个字,也是两行)
结论
目前来说,第三种方案的实现效果最好,也是我们正在线上使用的方式,推荐使用。