uniapp在小程序中使用createIntersectionObserver的问题

本文介绍了如何通过IntersectionObserverAPI优化项目性能,避免了传统滚动监听的复杂性。文章详细讲解了API的使用方法,提供了Vue3的代码示例,并提到了微信小程序和支付宝小程序的兼容性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

之所以是用这个Api,主要是为了优化项目。这个不光是可以用来实现图片的懒加载,还特别契合用于项目中的埋点。

优化之前:在页面加载以后获取元素节点的位置+滚动方式来做的。缺点显而易见,代码量比较多,而且监听scroll滚动官方也不推荐,非常影响性能。

优化之后:统一封装Class类,全局统一存储并处理createIntersectionObserver的监听。封装以后可以实现,横向滚动以及竖向滚动到可视区内都可以做到精准埋点。

使用方法在这里插入图片描述

options的三个属性:

  • thresholds:是一个数组,比如你可以设置[0.2,0.5,1]那么在视口区域相交部分达到20%、50%、100%都会触发监听。
  • initialRatio:默认是0,这个参数基本不用改动的。
  • observeAll:这个属性主要是用来监听多个类名一样的数据

IntersectionObserver 4个的方法

  • relativeTo:以你选中的节点作为容器区域,并根据你传入的节点类名进行监听,当传入的类名出现在容器内就会触发。
  • relativeToViewport:以你传入的选择器节点只要出现在视口区域就会触发监听。
  • observe:传入需要监听的类名,回调函数 callback 包含一个参数 result
  • disconnect:取消监听,隐藏或者卸载可取消监听。

vue3-代码示例

vue3中因为没有this,使用getCurrentInstance()

代码封装:

class ScrollObserver {
    #instance;
    #listeners;
    constructor() {
        this.#instance = getCurrentInstance();
        this.#listeners = {};
    }
    static createObserver(selector, thresholds, observeAll = false) {
        // 存在已经有的类名,则会报错,需要先取消监听
        if (this.#listeners[selector]) this.#listeners[selector].disconnect();
        this.#listeners[selector] = uni.createIntersectionObserver(this.#instance, {
            thresholds,
            observeAll,
        });
        return this.#listeners[selector];
    }
    on(selector,callback,observeAll = false) {
    	// 这里的监听[]可根据业务情况自行调整,监听满足条件是会重复触发
        this.constructor.createObserver(selector, [0, 0.2, 1], observeAll)
            .relativeToViewport({ right: 10 })
            .observe(selector, (res) => {
                callback(res);
            });
    }
    // 取消
    off(selector){
        if (!this.#listeners[selector]) return
        this.#listeners[selector].disconnect();
        Reflect.deleteProperty(this.#listeners, selector);
    }
}

margins: 用来扩展(或收缩)参照节点布局区域的边界
这里margin我是用的,{ right: 10 }。按照正常理解应该是当元素滑动到可视区域bottom以下才对,不过这个bottom是距离下边界的距离,相当于还是在元素内部。实际开发也可以修改参数进行微调测试。

使用示例:

// 实例化对象
const emitter = new ScrollObserver();
emitter.on('.example', (res) => {
     if (res.intersectionRatio === 1) {// 业务代码 }
     if (res.intersectionRatio === 0) {// 业务代码}
 });

存在的问题

  • 微信小程序:可以使用scss >>> 穿透语法实现组件的类名监听
  • 支付宝小程序:不可以使用 >>>,目前没有更好的办法兼容,官方推荐使用this.createIntersectionObserver,不过vue3并没有this。
  • 对已存在监听的类名,方法会抛出错误,需要先取消监听,然后再重新创建。
  • 页面的onhide或者onshow以后,虽然是出现在了当前可视区域,这种情况是没有触发监听的。

总结

在小程序开发中,使用这个Api来实现埋点的数据上报,基本是相当精准的,而且不会对性能造成影响。

### uni-app 中 `createIntersectionObserver` 的使用方法 #### 基本概念 `createIntersectionObserver` 是 UniApp 提供的一个 API,用于创建交集观察器 (Intersection Observer),可以监听某个目标节点与另一个区域(通常是视口或其他指定节点)的相交状态变化。这个功能类似于原生浏览器中的 Intersection Observer API[^3]。 #### 创建交集观察器 通过调用 `this.createIntersectionObserver(options)` 可以创建一个交集观察器实例。参数 `options` 是可选的配置项,支持以下属性: - **threshold**: 定义触发回调的比例阈值,默认为 `[0]`。 - **initialRatio**: 初始相交比例,默认为 `0`。 - **observeAll**: 是否观察所有目标节点,默认为 `false`。 示例代码如下: ```javascript const observer = this.createIntersectionObserver({ threshold: [0, 0.5, 1], initialRatio: 0, observeAll: false }); ``` #### 设置目标节点和相对节点 要监听的目标节点需要通过 `.relativeTo()` 或 `.relativeToViewport()` 来设置其相对于哪个区域进行比较。以下是两种常见的方式: 1. **相对于视口** 如果希望检测目标节点是否进入屏幕可视范围,则可以使用 `.relativeToViewport()` 方法。 ```javascript observer.relativeToViewport({ top: -50 }).observe('.target-selector', function(res) { console.log('目标节点进入了视口:', res.intersectionRatio); }); ``` 2. **相对于其他节点** 如果希望检测两个节点之间的相交情况,则可以使用 `.relativeTo()` 方法来绑定参考节点的选择器或 ID。 ```javascript observer.relativeTo('#reference-node-id').observe('.target-selector', function(res) { console.log('目标节点与参考节点相交:', res.intersectionRatio); }); ``` #### 获取节点信息 当目标节点的状态发生变化时,会触发回调函数并返回包含当前相交信息的对象 `res`。该对象的主要字段有: - **intersectionRect**: 表示两者的重叠部分矩形框。 - **boundingClientRect**: 目标节点自身的边界矩形框。 - **intersectionRatio**: 当前可见面积占总目标节点面积的比例。 - **id**: 节点对应的唯一标识符。 #### 示例代码 下面是一个完整的例子,展示如何利用 `createIntersectionObserver` 检测图片是否完全加载完成后再显示给用户。 ```html <template> <view class="container"> <image id="lazy-image" src="/static/lazy.jpg"></image> </view> </template> <script> export default { mounted() { const observer = this.createIntersectionObserver(); observer.relativeToViewport().observe('#lazy-image', ({ intersectionRatio }) => { if (intersectionRatio > 0) { // 图片进入视口 console.log('图片已进入视口'); // 此处可以执行懒加载逻辑或者动画效果 observer.disconnect(); // 不再继续监听 } }); }, }; </script> ``` --- ### 注意事项 1. 需要在组件生命周期内的上下文中调用 `this.createIntersectionObserver`,因为它是依赖于 Vue 组件实例的方法。 2. 对于多个目标节点的情况,如果设置了 `observeAll: true`,则每次都会收到对应数量的结果数组。 3. 在不再需要观察的情况下记得调用 `observer.disconnect()` 清除资源占用[^4]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值