时间:2023-06-09 22:15:01 | 来源:网站运营
时间:2023-06-09 22:15:01 来源:网站运营
小程序瀑布流组件:支持翻页与图片懒加载:电商小程序中,用到瀑布流的地方非常多,每次都写一个瀑布流,重复一次逻辑,作为程序员,肯定是非常不愿意的。.├── 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,就能访问彼此实例对象及其属性和方法。<view class="waterfall custom-class"> <view class="waterfall-inner"> <slot ></slot> </view></view>
同样,waterfall-item.wxml代码实现也非常简单,只有5行代码:<view class="waterfall-item custom-class" style="{{position}}:0;top:{{(top >= 0 ? top + 'px' : 0 + 'rpx')}};"> <slot ></slot></view>不知道slot用法的童鞋,请参考微信小程序自定义组件模板和样式文档。
// 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生命周期钩子。// 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方法中,我们调用了父组件上的方法// 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重排结束后,瀑布流渲染完成。<view 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})
itemGap = waterfall宽度 - (waterfall-item宽度 * 2)
在<waterfall> 的ready钩子中,可以获取到<waterfall>组件的宽度;同理,在<waterfall-item>的ready钩子中,可以获取到<waterfall-item>组件的宽度。// this.leftHeights += height + itemGap;// or// this.rightHeights += height + itemGap;
具体代码实现请查看源码关键词:图片,支持,瀑布,程序