flac3d命令流实例大全_小程序瀑布流组件:支持翻页与图片懒加载

(给前端大全加星标,提升前端技能)

作者:老人羽海

https://segmentfault.com/a/1190000022680541

电商小程序中,用到瀑布流的地方非常多,每次都写一个瀑布流,重复一次逻辑,作为程序员,肯定是非常不愿意的。


瀑布流的形式都是大同小异,不同的是瀑布流中每个模块的内容,随业务而变化。
所以,我们把瀑布流框架抽象成组件,瀑布流的内容由业务确定。这样即可实现组件化和自定义的最大平衡,微信小程序组件源码。


首先,我们来看一下瀑布流组件在实际项目中的实际效果。


1 实际效果

瀑布流组件实际效果如下图所示,左侧为用户交互效果,右侧为图片懒加载实际效果。

0c83f0059c82b83e7d347c1a99e4cba1.gif

2 什么是瀑布流?

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,waterfall-item宽度固定,高度不定,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。如下图所示:

6c7d60464cff5c42ef5843700a072de4.gif

3 实现功能

该瀑布流组件实现了以下几个功能:

  • 支持图片懒加载
  • 支持上拉数据翻页
  • 支持自定义样式
  • 支持瀑布流Item间隔底层自动计算
  • 原生组件模式:即类swiper和swiper-item 组件用法
  • 组件与数据完全解耦


4 实现原理

4.1 waterfall 和waterfall-item实现原理

第一步:在 waterfall-layout 目录下创建 waterfall 和 waterfall-item 组件,目录结构如下:

.├── query-node.js├── waterfall-item.js├── waterfall-item.json├── waterfall-item.wxml├── waterfall-item.wxss├── waterfall.js├── waterfall.json├── waterfall.wxml└── waterfall.wxss

第二步:分别在waterfall.js 和 waterfall-item.js的relations选项中指定组件父、子级关系:

// waterfall.jsComponent({    // ... other code    relations: {    './waterfall-item': {      type: 'child',    },    // ... other code  }})
// waterfall-item.jsComponent({    // ... other code    relations: {    '././waterfall': {      type: 'parent',    },    // ... other code  }})

指定彼此的父、子组件的关系后,即可通过 this.getRelationNodes 原生 API,就能访问彼此实例对象及其属性和方法。

第三步:实现waterfall.wxml 和 waterfall-item.wxml代码:

waterfall.wxml代码实现非常简单,只有5行代码:

class="waterfall custom-class">  <view class="waterfall-inner">    <slot >slot>  view></view>

同样,waterfall-item.wxml代码实现也非常简单,只有5行代码:

  class="waterfall-item custom-class"  style="{{position}}:0;top:{{(top >= 0 ? top + 'px' : 0 + 'rpx')}};">  <slot >slot></view>

不知道slot用法的童鞋,请参考微信小程序自定义组件模板和样式文档。

4.2 瀑布流原理

其实,不管是微信小程序、web、还是原生APP,瀑布流的实现原理都是一样的。都可以绝对定位和位置计算来实现。


瀑布流的大体过程如下图所示:


第一步:数据通过this.setData从逻辑层传输到视图层,进行第一渲染,由于每个waterfall-item 的top:0; 和 position:left;,所以都重叠了在一起。


第二步:通过节点查询API获取每个waterfall-item元素信息,并且计算出正确的top和position值。


第三步:setData每个waterfall-item的top和position,实现重排。

3c637cb92dba877308d9910689f0c452.png

具体逻辑实现如下:

首先,我们来实现一个节点查询API querySelector,之后会用到:

// query-node.js/** * 获取当前页面中,选择器为 selector 的第一个node节点 * @param {String} selector 符合微信小程序规范的选择器 * @param {Object} context 调用环境,普通页面中为wx,自定义组件中为this;默认值为wx. * @return {Array} 返回一个数组,第一个元素为 node 节点 */export const querySelector = function (selector, context = wx) {  return new Promise((resolve, reject) => {    context.createSelectorQuery()    .select(selector)    .boundingClientRect((res) => {      if (res) {        resolve(res);      } else {        reject(`不存在选择器为 ${selector} 的节点`);      }    })    .exec();  })};

接着,看一下组件waterfall 和waterfall-item在实际项目中的用法:

   <waterfall      loading="{{loadMorePending}}"      isAllLoaded="{{isAllLoaded}}"    >      <block wx:for="{{data.sections}}" wx:key="id" wx:for-item="product">        <waterfall-item          index="{{index}}"          custom-class="flow-item-wrapper"        >          <view class="product-item">            业务代码          view>        waterfall-item>      block>    waterfall>

当第一个waterfall-item组件,在视图层布局完成后会执行ready生命周期钩子。


在 ready 生命周期钩子中,我们需要做两件事:

  • 获取父组件waterfall的实例对象,并挂载在waterfall-item组件的 this实例对象上。因为之后我们需要在waterfall-item组件中修改waterfall上的数据。
  • 获取waterfall-item组件的高度,计算waterfall-item组件的位置信息top和position。
// waterfall-item.jsimport { querySelector } from './query-node';Component({  // ... other code  lifetimes: {    ready() {      const [waterfall] = this.getRelationNodes('./waterfall');      this.parent = waterfall;      this.setWaterfallItemPosition();    },  }  methods:{    async setWaterfallItemPosition() {      querySelector('.waterfall-item', this)        .then(async (node) => {          const { top, position } = await this.parent.getWaterfallItemPostionInfo(node);          this.setData({            top,            position          })        })    },  }  // ... other code})

在setWaterfallItemPosition方法中,我们调用了父组件上的方法

this.parent.getWaterfallItemPostionInfo,获取当前waterfall-item组件的top和position信息。并把已经渲染好的waterfall-item组件的累计高度缓存在waterfall的leftHeights和rightHeights属性上,用于计算下一个waterfall-item组件位置,主要逻辑如下:

// waterfall.jsconst POSITION_LEFT = 'left';const POSITION_RIGHT = 'right';Component({  // ... other code  /**   * 组件的方法列表   */  methods: {    lifetimes: {      ready() {        this.initParams();      }     },    initParams() {      this.leftHeights = 0;      this.rightHeights = 0;    },    /**     * 设置 waterfall-item 的高度值     * @param {Object} node waterfall-item 组件位置尺寸数据     */    async getWaterfallItemPostionInfo(node) {      let top = 0;      let position = POSITION_LEFT;      const { height } = node;      const { itemGap } = this;      if (this.leftHeights <= this.rightHeights) {        top = this.leftHeights;        if(this.leftHeights === 0) {          this.leftHeights += height;        } else {          top += itemGap;          this.leftHeights += (height + itemGap);        }      } else {        position = POSITION_RIGHT;        top = this.rightHeights;        if(this.rightHeights === 0) {          this.rightHeights += height;        } else {          top += itemGap;          this.rightHeights += (height + itemGap);        }      }      return {        top,        position,      }    }    // ... other code  }})

当所有的waterfall-item重排结束后,瀑布流渲染完成。

4.3 图片懒加载原理

微信小程序中,标签本身是支持懒加载的,当lazy-load={{true}},且在即将进入一定范围(上下三屏)时才开始加载。


也就是说,当lazy-load={{true}},标签初次渲染在视口上下三屏之外时,是不会请求图片资源的,当即将进入三屏之内时,才会加载。


在4.2小节的图3中,的初始化位置设置成了top:0; 和 position:left;,所以,都在视口中。如果将top的值成三屏之外的数值,例如,400vh或者更大,则重排之后,任然在三屏之外的图片即会自动懒加载。

  class="waterfall-item custom-class"  style="{{position}}:0;top:{{(top >= 0 ? top + 'px' : itemCount * 100 + 'vh')}};">  <slot >slot></view>
Component({  // waterfall-item.js  // ... other code  lifetimes: {    ready() {      const { itemCount } = this.data;      const [waterfall] = this.getRelationNodes('./waterfall');      waterfall.childCount += 1;      this.parent = waterfall;      this.setData({        itemCount: itemCount + waterfall.childCount,      })    },  },  // ... other code})

4.4 数据翻页

因为实现了wx:for 功能,和组件一样,因此翻页逻辑完全由用户自己定制,和只给你提供翻页的功能,组件就可以和瀑布流数据结构完全解耦。

4.5 瀑布流Item间隔底层自动计算

将列和行中,两个组件之间的距离定义为itemGap,则:

itemGap = waterfall宽度 - (waterfall-item宽度 * 2)

在 的ready钩子中,可以获取到组件的宽度;同理,在的ready钩子中,可以获取到组件的宽度。
在调用getWaterfallItemPostionInfo之前,获取到itemGap的值即可。这样,在计算的top值时,除了第一行的的top值等于0之外,其他所有的top值等于:

// this.leftHeights += height + itemGap;// or// this.rightHeights += height + itemGap;

具体代码实现请查看源码


5 总结

通过瀑布流框架抽象,使和接近原生组件使用体验,同时使组件与数据完全解耦。通过巧妙的初始化位置top设置,使瀑布流具图片有懒加载的功能。

推荐阅读   点击标题可跳转

微前端在小米 CRM 系统的实践

前22年的Loser,后4年和自己赛跑的人 | 最惨前端面经

前端面试之 Vue 向技巧总结

觉得本文对你有帮助?请分享给更多人

关注「前端大全」加星标,提升前端技能

870a76c9002cf3f023c0fb8f185e3b1a.png

好文章,我在看❤️

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值