在小程序不断迭代的时候,很容易遇到首屏渲染问题。这种问题,可能出现的缘由是:小程序包太大,资源须要加载;网络环境太差,下载速度太慢;渲染节点太多,渲染耗时。css
针对小程序首次加载包的问题,小程序提出了分包加载的功能,这里不作详细描述,能够去看下官方文档html
这里我选择的是针对渲染节点去作优化。git
在微信的API文档里面,有一个判断节点与可视区域的APIgithub
IntersectionObserver 对象,用于推断某些节点是否能够被用户看见、有多大比例能够被用户看见小程序
这个时候就在想,能不能创建IntersectionObserver
跟组件之间的关系,使得组件进入可视区域的时候,就显示本身的内容,不然隐藏本身,这样达到动态加载模块的目的。微信
// 伪代码
// 创建监听
element.observer()
// 处理进入
observer.handleEnterView(() => {
callback() // 处理回调
disconnect() // 销毁
})
复制代码
<!-- component -->
<view class="component">
<view class="component-header"></view>
<view class="component-observer" wx:if="{{ observer_status}}"></view>
<view class="component-content" wx:else>
<!-- your content -->
</view>
</view>
复制代码
创建了基本技术方案以后,就开始到代码层面了网络
Component({
data: {
observer_status: true
},
// 在ready写是由于组件在这个时候,才在视图层布局完成
ready () {
// 由于咱们是把设备的整个可视区域当成了观参照区域,因此这里直接选择relativeToViewport,若是须要其余的观察区域能够调用relativeTo选择参照区域
this.observer = this.createIntersectionObserver().relativeToViewport()
// 我这里的作法是,只要观察的节点进入了可视区域,就显示本身自己的内容
// 实际上这个observer的回调触发时机是观察节点进入或者离开可视区域,我这里选择的是,只要执行了就显示这个区域,而且关闭这个观察
this.observer.observe('.observer', (res) => {
this.setData({
observer_status: false
})
this.observer.disconnect()
this.observer = null
})
},
detached () {
// 若是未进入可视区域就离开了,也须要销毁本身的观察
this.observer && this.observer.disconnect()
}
})
复制代码
大家觉得这就完了么,并无。app
对于一个小程序页面,它是能够由template或者Component组成的。对于template来讲,须要在Page里面定义,并且若是观察的东西比较多的话,须要设置observeAll:all
,可是官方文档里面有说同时选中过多节点,将影响渲染性能。ide
对于组件开发来讲,若是每一个组件都这样写的话,是否也会跟observerAll:all
同样影响渲染性能,还不清楚,若是确实会影响的话也只能减小观察对象,或者把作一个大容器去观察。可是若是每一个组件都这样写的话也会很是的繁琐。布局
这个时候,组件的好处就来了。在定义组件的时候,有一个很神奇的属性,他就是behaviors
。简单点说,他其实就是一个代码复用机制。直接使用behaviors
可使得组件自动得到某些方法,属性。利用这个特性,就能够在组件里面少写不少代码了。
// mixin.js
module.exports = Behavior({
data: {
observer_status: true
},
ready () {
this.observer = this.createIntersectionObserver().relativeToViewport()
// 本身统一好observer节点的class
this.observer.observe('.component-observer', (res) => {
this.setData({
observer_status: false
})
this.observer.disconnect()
this.observer = null
})
},
detached () {
this.observer && this.observer.disconnect()
}
})
复制代码
// Component.js
let mixin = require('你的mixin路径')
Component({
behaviors: [mixin]
})
复制代码
<!-- Component.wxml -->
<view class="component">
<view class="component-header"></view>
<view class="component-observer" wx:if="{{ observer_status}}"></view>
<view class="component-content" wx:else>
<!-- your content -->
</view>
</view>
复制代码
或者你能够把整个observer作成组件,这样去减小observer的数量,内聚一些模块
<!-- Observer.wxml -->
<view class="observer">
<view class="observer-element" wx:if="{{ observer_status}}"></view>
<view class="observer-content" wx:else>
<slot/>
</view>
</view>
复制代码
须要注意的是对于组件来讲,若是observer的话就须要一个观察节点,而且这个观察节点必须是高度不为0的可视对象,若是又想有高度又不想影响页面位置的话能够用一些hack的方法
.component-observer {
height: 1rpx;
margin-top: -1rpx;
}
复制代码
在使用IntersectionObserver
的时候,有试过用hidden
属性。可是实际上,hiiden
也是会被渲染出来的,只是不显示而已,并不会形成页面加载速度的提高
这里是随便拿的一个demo去弄的,须要的话能够点击这里
或者浏览小程序代码片断https://developers.weixin.qq.com/s/oV1RFfmY7H4W
使用以前
使用以后
若是图片不动的话能够点击查看 能够看得出是提高是至关明显的
image有一个lazy-load
的属性,可是它只能在page以及在scroll-view使用,若是在其余地方的话是否是也能够用这个去作呢
<!-- image-compponent -->
<view class="observer-picture">
<image src="{{ _src }}"></image>
</view>
复制代码
// image-component js
Component({
properties:{
imageSrc: {
type: String,
value: '',
},
},
data: {
_src: "default_image"
},
ready () {
// 伪代码
observer('.observer-picture')
.then(() => {
this.setData({
_src: this.properties.imageSrc
})
})
}
})
复制代码
对于在普通view里面,若是须要作到底加载的话有scroll-view去作,可是这个性能会比较差,容易出现卡顿,这样也能够本身封装一层以后用这个去实现
第一次在这里发表文章,欢迎你们一块儿讨论,交流心得