开门见山的说,小程序做到那种一页全是图片的页面,公司要求优化,好的,图片优化想到两点:
分页
图片懒加载
分页就不说了,大家搜索一下就知道怎么写
下面,开始讲讲小程序的图片懒加载效果吧
既然要懒加载,那么肯定是要监听节点和滚动条的,也就是说,一开始给图片一个默认的图片地址占位,或者直接不给,就给他一个默认的位置就好了,等节点滚到屏幕内的位置后再去把默认的地址替换成真实路径就ok。
既然要监听滚动条,那就需要去优化一下滚动条,考虑到是高频触发的函数,小程序的onPageScroll这个就是监听滚动条的钩子,知道了这个就去utils这个文件夹去创建公共的函数吧
这个文件一般放公共的函数
开始定义
function throttle(fn, interval) {
var enterTime = 0;//触发的时间
var gapTime = interval || 300;//间隔时间,如果interval不传,则默认300ms
return function () {
var backTime = new Date();//第一次函数return即触发的时间
if (backTime - enterTime > gapTime) {
fn.call(this, arguments);
enterTime = backTime;//赋值给第一次触发的时间,这样就保存了第二次触发的时间
}
};
}
然后抛出这个函数
module.exports = {
throttle: throttle
}
接下来需要用到图片懒加载的去引入这个js文件
const utils = require('../../utils/util.js')
接下来就是在onPageScroll里去看看ok不ok
这样写
onPageScroll: utils.throttle(function(){
console.log(11233)
})
很好,成功节流
下面考虑图片懒加载
因为图片在实际开发中是后端人员传给我们的json数组或者数组对象,我们前端需要去循环,或者嵌套循环才能在页面显示图片,就想着封装成组件,把数据单独分发给组件去处理,这样就不用去单独去循环监听或者双重循环去监听图片是否显示在屏幕内
我们先建立一个目录component,用于存放组件,再建目录lazyLoadImg,然后建立component,命名lazyLoadImg,这就是我们的图片懒加载组件了
然后lazyLoadImg.wxml里这样写
<view class="lazyLoadImg" style="background-image:url({{show ? imgUrl : defaultImgUrl}})"></view>
这个就是我们的组件了
laztLoadImg.wxss
.lazyLoadImg{
width: 100%;
height: inherit;
background-repeat: inherit;
background-size: inherit;
transition: inherit;
border-radius: inherit;
display: block;
position: absolute;
}
lazyLoadImg.js
Component({
/**
* 组件的属性列表
*/
properties: {
clientH: String,
imgUrl: String
},
/**
* 组件的初始数据
*/
data: {
clientH:'',
show: false,
defaultImgUrl:'/lib/images/defaultAvater.jpg', //默认的图片地址
canIUse: wx.canIUse('createIntersectionObserver'),
imgUrl:''
},
/**
* 组件的方法列表
*/
methods: {
// 兼容 1.9.3 微信版本库
_lazyLoadImgHeightVersion: function(){
let that = this
let intersectionObserver = this.createIntersectionObserver()
intersectionObserver.relativeToViewport().observe('.lazyLoadImg', function(ret){
if (ret.intersectionRatio > 0) {
intersectionObserver.disconnect()
that.setData({
show: true
})
}
})
},
// 兼容1.4.0 微信版本库
_lazyLoadImgLowVersion: function(){
let that = this
if (!this.data.show) {
const query = this.createSelectorQuery();
query.select('.lazyLoadImg').boundingClientRect();
query.selectViewport().scrollOffset();
query.exec(function (res) {
if (res[0].top < that.data.clientH) {
that.setData({
show: true
})
}
})
}
},
// 判断父组件是否启用低版本的图片懒加载
judgeVersion:function(){
if (!this.data.canIUse){
this._lazyLoadImgLowVersion()
}
}
},
attached: function(){
// 节点未渲染,现在只能去setData
this.setData({
clientH: this.properties.clientH,
imgUrl: this.properties.imgUrl
})
},
ready: function(){
// 页面渲染完毕,现在可以去获取节点
if (!this.data.canIUse) {
this._lazyLoadImgLowVersion()
}else{
this._lazyLoadImgHeightVersion()
}
}
})
记住要再调用组件的json里引用
{
"usingComponents": {
"lazyLoadImg": "/component/lazyLoadImg/lazyLoadImg"
}
}
然后调用组件的页面wxml
<view wx:for="{{50}}" wx:key="index" class="lazyLoadBox">
<lazyLoadImg class="lazyLoad" clientH="{{clientH}}" imgUrl="{{imgUrl}}"></lazyLoadImg>
</view>
这里面的循环我写的是死的,具体根据项目写,imgUrl是请求后台返回来图片的地址
别忘了要去获取屏幕的高,我写在app.js里
app.js
onLaunch: function () {
let vm = this
wx.getSystemInfo({
success: function(res) {
let clientHeight = res.windowHeight;
vm.globalData.clientHeight = clientHeight
},
})
},
globalData: {
clientHeight: ''
}
调用组件页面的js文件
const app = getApp(),
utils = require('../../utils/util.js')
Page({
data: {
clientH: app.globalData.clientHeight,
imgUrl:"XXXXX.jpg" //这里的图片我随便找的一张网络图, 真实开发不需要写
},
onLoad: function () {
},
onReady: function(){
// 在页面渲染完毕的时候去查找所有组件,这个一般项目是写在请求完回来的回调里,我这里是死的所以写onReady
this.lazyLoadImg = this.selectAllComponents('.lazyLoad')
},
// 监听页面滚动条,去循环调用每个子组件的内部函数,这里注意不能用箭头函数()=>{} 会造成this指向不对
onPageScroll: utils.throttle(function(){
for (var i in this.lazyLoadImg) {
this.lazyLoadImg[i].judgeVersion()
}
})
})
父页面的wxss
比较重要的是这个
.lazyLoad{
width: 100%;
height: inherit;
background-repeat: inherit;
background-size: inherit;
transition: inherit;
border-radius: inherit;
display: block;
position: absolute;
}
因为背景图片样式是继承父盒子的
父盒子就根据需求去改css样式
.lazyLoadBox{
position: relative;
background-size: contain;
border-radius: 8rpx;
height: 600rpx;
background-repeat: no-repeat;
transition: .5s;
width:500rpx;
margin: 0 auto;
margin-bottom: 30rpx;
}
撸码完毕,滑动起来丝滑顺畅