- 图片懒加载组建(简单版)
话不多说 直接上效果图 [视频] 起因: 当时使用了官方的 image 里面的 lazy-load 的 属性, 发现在 net work 上, 并没有实际上的效果(我的图片设置的展示比例比较小, 且也做了分页的效果, 呈现出来的 数据差不多刚好两屏的样子), 而官方的文档上说的是 图片懒加载,在即将进入一定范围(上下三屏)时才开始加载, 这就很明显不是我想要的效果~ 解决方法: 当时搜索了网上的信息, 无非都是通过数据源去做处理(要么统一在请求数据做处理, 还有就是在 滚动的时候去监听, 导致如果每个页面都需要使用的时候, 都需要引入改方法 或者 需要相同的数据格式, 我觉得很行), 再三思索下, 决定自己实现一个图片懒加载 我自己的解决思路(仅供参考)我使用的方法 有两个 监听屏幕的滑动情况元素是否出现在了屏幕上实现以上的方法, 就分别需要用到两个 官方的 api [图片][图片] 有了这两个方法, 就可以知道 我们需要的监听的图片是否有出现在图片的哪个位置了(需要特别指定位置) wxml 页面(可以封装成一个图片的组建, 方便拓展) // wxml <image width="{{width}}" height="{{height}}" class="imgContent" src="{{show ? src : ''}}"/> js 页面 // js /** * 监听元素是否出现在屏幕 * @param { String } elName 所在的节点 * @param { String } attr 需要获取的属性值 * { * dataset // 节点的dataset * width // 节点的宽度 * height // 节点的高度 * scrollLeft // 节点的水平滚动位置 * scrollTop // 节点的竖直滚动位置 * scrollX // 节点 scroll-x 属性的当前值 * scrollY // 节点 scroll-y 属性的当前值 * * // 此处返回指定要返回的样式名 * res.margin * res.backgroundColor * res.context // 节点对应的 Context 对象 * } * @param { Boolean } isComponent 是否在组建内使用 * * @return {Function} 一个promise */ function listenEltoScreen({ elName = '', attr = '', value = '', isComponent = {} } = {}) { return new Promise((resolve) => { const query = !isComponent ? wx.createIntersectionObserver() : this.createIntersectionObserver() query.relativeToViewport({ [attr]: value }).observe(elName, (res) => { resolve(res) }) }) } Component({ /** * 组件的属性列表 */ properties: { // 图片链接 src: { type: String, value: '' }, width: { type: String, value: '100%' }, height: { type: String, value: '100%' }, // 是否触发懒加载(暂不支持动态修改 触发懒加载) lazy: { type: Boolean, value: true }, // 触发懒加载的阀值 threshold: { type: Number, value: 20 }, // 触发懒加载的方向 direction: { type: String, value: 'bottom' } }, /** * 组件的初始数据 */ data: { show: false }, ready() { if (!this.data.lazy) return // 监听 元素是否有距离屏幕的情况 listenEltoScreen.bind(this)({ elName: '.imgContent', attr: this.data.direction, value: this.data.threshold, isComponent: true }).then(() => { console.log('触发了') this.setData({ show: true }) }) } }) 以屏幕为一个检测点, 来以此判断 需要监听的元素是否有出现在屏幕上(实现原理), 实现的效果可以看顶部的视频, 个人的一个小懒加载, 可以适用在任何一个需要图片的页面, 也可以在此基础上拓展 代码片段: https://developers.weixin.qq.com/s/hXnoTpmE7RtD (如果对你有帮助, 给个赞吧, 比较花了点时间研究)
2021-09-18 - 小程序图片懒加载终极方案
效果图 既然来了,把妹子都给你。 [图片] 定义懒加载,前端人都知道的一种性能优化方式,简单的来说,只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。 实现原理监听页面的[代码]scroll[代码]事件,判读元素距离页面的[代码]top[代码]值是否是小于等于页面的可视高度 判断逻辑代码如下 [代码]element.getBoundingClientRect().top <= document.documentElement.clientHeight ? 显示 : 默认[代码] 我们知道小程序页面的脚本逻辑是在JsCore中运行,JsCore是一个没有窗口对象的环境,所以不能在脚本中使用window,也无法在脚本中操作组件。 所以关于图片懒加载就需要在数据上面做文章了。 页面页面上面只需要根据数据的某一个字段来判断是否显示图片就可以了,字段为Boolean类型,当为false的时候显示默认图片就行了。 代码大概长成这样 <view wx:for="{{list}}" class='item item-{{index}}' wx:key="{{index}}"> <image class="{{item.show ? 'active': ''}}" src="{{item.show ? item.src : item.def}}"></image> </view> 布局跟简单,[代码]view[代码]组件里面有个图片,并循环[代码]list[代码],有多少就展示多少 [代码]image[代码]组件的[代码]src[代码]字段通过每一项的[代码]show[代码]来进行绑定,[代码]active[代码]是加了个透明的过渡 样式 image{ transition: all .3s ease; opacity: 0; } .active{ opacity: 1; } 逻辑 本位主要讲解懒加载,所以把数据写死在页面上了 数据结构如下: [图片] 我们使用两种方式来实现懒加载,准备好没有,一起来快乐的撸码吧。 WXML节点信息 小程序支持调用createSelectQuery创建一个[代码]SelectorQuery[代码]实例,并使用[代码]select[代码]方法来选择节点,并通过[代码]boundingClientRect[代码]来获取节点信息。 wx.createSelectorQuery().select('.item').boundingClientRect((ret)=>{ console.log(ret) }).exec() 显示结果如下 [图片] 悄悄告诉你,小程序里面有个[代码]onPageScroll[代码]函数,是用来监听页面的滚动的。 还有个[代码]getSystemInfo[代码]函数,可以获取获取系统信息,里面包含屏幕的高度。 接下来,思路就透彻了吧。还是上面的逻辑, 扒拉扒拉直接写代码就行了,这里只写下主要的逻辑,完整代码请戳文末github showImg(){ let group = this.data.group let height = this.data.height // 页面的可视高度 wx.createSelectorQuery().selectAll('.item').boundingClientRect((ret) => { ret.forEach((item, index) => { if (item.top <= height) { 判断是否在显示范围内 group[index].show = true // 根据下标改变状态 } }) this.setData({ group }) }).exec() } onPageScroll(){ // 滚动事件 this.showImg() } 至此,我们完成了一个小程序版的图片懒加载,只是思维转变了下,其实并没有改变实现方式。我们来学些新的东西吧。 节点布局相交状态 节点相交状态是啥?它是一个新的API,叫做[代码]IntersectionObserver[代码], 本文只讲解简单的使用,了解更多请猛戳没错,就是点我 小程序里面给它的定义是节点布局交叉状态API可用于监听两个或多个组件节点在布局位置上的相交状态。这一组API常常可以用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见。 里面设计的概念主要有五个,分别为 参照节点:以某参照节点的布局区域作为参照区域,参照节点可以有多个,多个话参照区域取它们的布局区域的交集目标节点:监听的目标,只能是一个节点相交区域:目标节点与参照节点的相交区域相交比例:目标节点与参照节点的相交比例阈值:可以有多个,默认为[0], 可以理解为交叉比例,例如[0.2, 0.5]关于它的API有五个,依次如下 1、[代码]createIntersectionObserver([this], [options])[代码],见名知意,创建一个IntersectionObserver实例 2、[代码]intersectionObserver.relativeTo(selector, [margins])[代码], 指定节点作为参照区域,margins参数可以放大缩小参照区域,可以包含top、left、bottom、right四项 3、[代码]intersectionObserver.relativeToViewport([margin])[代码],指定页面显示区域为参照区域 4、[代码]intersectionObserver.observer(targetSelector, callback)[代码],参数为指定监听的节点和一个回调函数,目标元素的相交状态发生变化时就会触发此函数,callback函数包含一个result,下面再讲 5、[代码]intersectionObserver.disconnect()[代码] 停止监听,回调函数不会再触发 然后说下callback函数中的result,它包含的字段为 [图片] 我们主要使用[代码]intersectionRatio[代码]进行判断,当它大于0时说明是相交的也就是可见的。 先来波测试题,请说出下面的函数做了什么,并且log函数会执行几次 1、 wx.createIntersectionObserver().relativeToViewport().observer('.box', (result) => { console.log('监听box组件触发的函数') }) 2、 wx.createIntersectionObserver().relativeTo('.box').observer('.item', (result) => { console.log('监听item组件触发的函数') }) 3、 wx.createIntersectionObserver().relativeToViewport().observer('.box', (result) => { if(result.intersectionRatio > 0){ console.log('.box组件是可见的') } }) duang,揭晓答案。 第一个以当前页面的视窗监听了[代码].box[代码]组件,log会触发两次,一次是进入页面一次是离开页面 第二个以[代码].box[代码]节点的布局区域监听了[代码].item[代码]组件,log会触发两次,一次是进入页面一次是离开页面 第三个以当前页面的视窗监听了[代码].box[代码]组件,log只会在节点可见的时候触发 好了,题也做了,API你也掌握了,相信你已经可以使用[代码]IntersectionObserver[代码]来实现图片懒加载了吧,主要逻辑如下 let group = this.data.group // 获取图片数组数据 for (let i in this.data.group){ wx.createIntersectionObserver().relativeToViewport().observe('.item-'+ i, (ret) => { if (ret.intersectionRatio > 0){ group[i].show = true } this.setData({ group }) }) } 最后 至此,我们使用两种方式实现了小程序版本的图片懒加载,可以发现,使用[代码]IntersectionObserver[代码]来实现不要太酸爽
2020-05-12