在小程序里面提供了createIntersectionObserver来实现监听目标元素与视窗的位置变化
wx.createIntersectionObserver(Object component, Object options)
利用这个API,可以轻松实现滚动定位功能:
实现的整体思路:
- 先实现根据页面的滚动,导航条高亮到具体的内容模块
- 再实现点击对应的导航,页面再滚动到具体的内容区域
1.1 实现页面的滚动,高亮具体的导航条
利用IntersectionObserver的方式实现:监听每个模块与viewport之间的距离变化
<template>
<view class="nav-position-box">
<text id="1' @tap="toViewClick(1)" :class="actionViewName == 1 ? 'isActive': ''">内容1</text>
<text id="2' @tap="toViewClick(2)" :class="actionViewName == 2 ? 'isActive': ''">内容2</text>
<text id="3' @tap="toViewClick(3)" :class="actionViewName == 3 ? 'isActive': ''">内容3</text>
</view>
<!-- 具体内容区 -->
<view id="content-1" class="observe-scroll-node">
..................
</view>
<view id="content-2" class="observe-scroll-node">
..................
</view>
<view id="content-3" class="observe-scroll-node">
..................
</view>
</template>
<script>
let node = [
{id: 'content-1', show: false},
{id: 'content-2', show: false},
{id: 'content-3', show: false},
];
export default class backTop extends wepy.component {
data = {
actionViewName: ''
}
// 页面滚动改变对应的导航信息
changeTypeByScroll() {
if (observerScrollNodeObj) {
observerScrollNodeObj.disconnect();
observerScrollNodeObj = null;
}
observerScrollNodeObj = wx.createIntersectionObserver(this.$wxpage, { observeAll: true });
observerScrollNodeObj
// 相对于页面可视区
.relativeToViewport({ top: -70 })
// 相对于某一个元素
.observe('.observe-scroll-node', res => {
this.observeNode(res);
this.$apply();
});
}
// 观察节点
observeNode({ intersectionRatio, id }) {
// 找到滚动到对应id下面的序号
const nodeIndex = node.findIndex(ele => ele.id === id);
// 将滚动到的版块的show属性设置为true
node[nodeIndex] && (node[nodeIndex].show = intersectionRatio > 0);
// 找到nav应该显示哪一个内容
this.actionViewName = node.findIndex(ele => ele.show);
this.$apply();
}
onLoad() {
this.changeTypeByScroll();
}
}
</script>
1.2 点击对应的导航,页面滚动到对应位置
<script>
// 锚点定位(点击topNav页面滑动到具体位置)
toViewClick(actionView) {
const query = wx.createSelectorQuery();
query.select(`#${actionView}`).boundingClientRect(); // 选择对应Id的节点,获取节点位置信息的查询请求
query.selectViewport().scrollOffset(); // 获取页面滑动位置的查询请求
query.exec((res) => {
if (res[0] && res[0].top) {
(actionView === 'swiper-list') && (this.backTopShow = false);
this.scrollPageHash(res[0].top, res[1].scrollTop, actionView);
this.$apply();
}
});
},
// 页面滚动函数
scrollPageHash(distance, scrollTop, actionView) {
const _ = this;
// 滚动的时候,断开连接
if (observerScrollNodeObj) {
observerScrollNodeObj.disconnect();
observerScrollNodeObj = null;
}
wx.pageScrollTo({
scrollTop: distance + scrollTop - 50,
duration: 200,
complete() {
// 改变节点的状态
const currentIndex = node.findIndex(ele => ele.id === 'content-'+actionView);
node.forEach((_, index) => {
if (index < currentIndex) {
_.show = false;
}
});
// 再链接监听
_.changeTypeByScroll();
}
});
}
</script>
这样就实现了页面的固定定位。
二. 实现图片懒加载
当图片没有出现在视窗里时,此时去加载图片资源比较消耗性能,那么如果在进入视窗才加载,可以很好的优化性能.
<view class="observe-image">
<block v-if=" item.show ">
<image class="gray-bg lottery-img" mode="aspectFill" :src="cover" ></image>
</block>
<block v-else>
<view class="gray-bg lottery-img"></view>
</block>
</view>
<script>
data() {
return {
cover: false
}
},
mounted() {
// 开启监听
this.createObserveInstance();
},
methods: {
async observerNode() {
// 先断开
this.disconnectObserve();
// 再链接
this.createObserveInstance();
observerInstance.relativeToViewport().observe('.observe-image', res => {
if (res.intersectionRatio > 0) {
// 开启image标签发送请求,没开启之前用view空白盒子占位
this.cover = true;
}
});
},
// 断开链接
disconnectObserve() {
if (observerInstance) {
observerInstance.disconnect();
observerInstance = null;
}
},
// 创建一个监听的IntersectionObserver实例
createObserveInstance() {
observerInstance = uni.createIntersectionObserver(this, {
observeAll: true
});
},
}
</scirpt>
上面使用uni的版本实现的.当滚动页面的时候就可以发现只有当内容出现时才会去发送下载图片的请求.