Intersection Observer API---交叉观察器 API

Intersection Observer API

        交叉观察器 API(Intersection Observer API)提供了一种异步检测目标元素祖先元素顶级文档视口相交情况变化的方法,例如,可以观察判断一个div(有大小的)盒子在是否出现在窗口(window)中,你也可以指定它的一个父级元素,像html,body,等等。

观察器对象

构造函数

let observer = new IntersectionObserver(entries => {
    
},{
    root: null,
    rootMargin: '0px',
    threshold: 0.5 // 出现50% 
})

callback:回调函数,有一个参数entries,

       entries:数组,存放描述观察器和被观察对象的状态的对象(被观察的对象可以有多个)---IntersectionObserverEntry

​           IntersectionObserverEntry:对象,内部有7个属性和值

                 boundingClientRect:返回包含目标元素的边界信息的DOMRectReadOnly. 边界的计算方式与 Element.getBoundingClientRect() 相同。

                intersectionRatio:返回intersectionRect 与 boundingClientRect 的比例值。

                intersectionRect:返回一个 DOMRectReadOnly 用来描述根和目标元素的相交区域。

                isIntersecting:返回一个布尔值,如果目标元素与交叉区域观察者对象 (intersection observer) 的根相交,则返回 true .如果返回 true, 则 IntersectionObserverEntry 描述了变换到交叉时的状态; 如果返回 false, 那么可以由此判断,变换是从交叉状态到非交叉状态。

                rootBounds:返回一个 DOMRectReadOnly 用来描述交叉区域观察者 (intersection observer) 中的根。

                target:与根出现相交区域改变的元素 (Element).

                time ​:返回一个记录从 IntersectionObserver 的时间原点 (time origin) 到交叉被触发的时间的时间戳 (DOMHighResTimeStamp).

option: 对象,内部有3个属性和值,

        root:根元素,用作视口的元素,用于检查指定元素的可见性,必须是该指定元素的祖先。如果未指定或为 null,则默认为浏览器视口。例如,一个div是body的子元素,那么body就可以是这个div的root。

        rootMargin:根元素周围的边距。其值可以类似于 CSS margin 属性,例如 "10px 20px 30px 40px"(上、右、下、左)。这些值可以是百分比。在计算交叉点之前,这组值用于增大或缩小根元素边框的每一侧。默认值为全零。

        threshold:阈值,一个数字或一个数字数组,表示目标可见度达到多少百分比时,观察器的回调函数就应该执行(当目标在根元素中出现指定的比例时会触发一次回调)。如果只想在能见度超过 50% 时检测,可以使用 0.5 的值。如果希望每次能见度超过 25% 时都执行回调,则需要指定数组 [0, 0.25, 0.5, 0.75, 1]。默认值为 0(这意味着只要有一个像素可见,回调就会运行)。值为 1.0 意味着在每个像素都可见之前,阈值不会被认为已通过。

 

可以看到实例化的观察器对象,

实例方法

disconnect()

        使 IntersectionObserver 对象停止监听目标。

observe()

        使 IntersectionObserver 开始监听一个目标元素。

ItakeRecords()

        返回所有观察目标的 IntersectionObserverEntry 对象数组。

unobserve()

        使 IntersectionObserver 停止监听特定目标元素。

观察示例

新建一个div盒子,当它出现在视口占50%时,改变它的颜色

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>视口观察</title>
    <style>
        .content{
            height: 200vh;
        }
        .box{
            width: 100px;
            height: 100px;
            background-color: red;
        }
    </style>
</head>
<body>
    <div class="content"></div>
    <div class="box"></div>
    <div class="content"></div>
    <script src="index.js"></script>
</body>
</html>

index.js:

const box = document.getElementsByClassName('box')[0];
const observer = new IntersectionObserver(entries => {
    // console.log(entries);
    // 如果 intersectionRatio 为 0,则目标在视野外,
    // 我们不需要做任何事情。
    if (entries[0].intersectionRatio <= 0) return;
    if(entries[0].isIntersecting >= observer.thresholds[0]){
        console.log('元素进入视口50%');
    }
},{
    root: null,
    rootMargin: '0px',
    threshold: 0.5 // 出现50% 
})
observer.observe(box);//观察box

console.log(observer);

再添加改变颜色

const box = document.getElementsByClassName('box')[0];
const observer = new IntersectionObserver(entries => {
    // // console.log(entries);
    // // 如果 intersectionRatio 为 0,则目标在视野外,
    // // 我们不需要做任何事情。
    // if (entries[0].intersectionRatio <= 0) return;
    if(entries[0].isIntersecting >= observer.thresholds[0]){
        console.log('元素进入视口50%');
        box.style.backgroundColor = 'blue';
    }else{
        console.log('元素离开视口50%');
        box.style.backgroundColor = 'red';
    }
},{
    root: null,
    rootMargin: '0px',
    threshold: 0.5 // 出现50% 
})
observer.observe(box);//观察box

console.log(observer);

 

这样就成功观察到了一个元素是否出现再视口,并对其进行操作,

实际应用中可以实现图片的懒加载,当视口中出现图片时在将图片加载出来 

<think>我们正在讨论在uni-app的H5项目中使用Intersection ObserverAPI进行元素可见性检测。根据提供的引用内容,特别是引用[1]和引用[2]中的示例,我们可以参考这些实现方式,但需要适配到uni-app的环境。在uni-app中,H5端的运行环境是浏览器,因此我们可以像在普通Web项目中一样使用IntersectionObserver API。不过,需要注意的是,uni-app的项目结构是Vue组件,因此我们需要在Vue组件的生命周期中正确使用。步骤:1.在组件的`mounted`生命周期钩子中,我们可以获取DOM元素并设置观察。2.使用`document.querySelector`或`this.$refs`来获取DOM元素(推荐使用`this.$refs`以符合Vue的习惯)。3.创建IntersectionObserver实例,并传入回调函数和配置选项。 4.在回调函数中处理元素进入视口时的逻辑(例如添加类名、加载图片等)。5.在组件销毁前,如果需要,可以停止观察(在`beforeUnmount`或`unmounted`钩子中)。示例:实现一个当元素进入视口时添加类名的效果。假设我们有一个列表,每个列表项需要在其进入视口时显示(通过添加类名来实现动画效果)。 模板部分(在.vue文件中):```html<template><view><ul><li v-for="(item, index) inlist":key="index" ref="listItems">{{item }}</li></ul></view></template> ```脚本部分: ```javascript<script>export default{data(){return {list: ['Item1', 'Item2','Item3',...]//你的列表数据};},mounted() {//注意:在uni-appH5中,我们可以使用nextTick确保DOM已经渲染this.$nextTick(() =>{//使用refs获取所有li元素const listItems =this.$refs.listItems;if (listItems) {//创建观察者实例constobserver =new IntersectionObserver(entries=> {entries.forEach(entry =>{if (entry.isIntersecting) {//当元素进入视口时,添加类名entry.target.classList.add('show');//停止观察该元素(可选)observer.unobserve(entry.target);}});}, {root:null,//相对于视口rootMargin:'0px',threshold:0.1 //当元素10%进入视口时触发});//观察每个列表项listItems.forEach(item=> {observer.observe(item);});//保存观察者实例,以便在组件销毁时断开连接(可选,但推荐)this.observer =observer;}});},beforeUnmount() {//在组件销毁前,断开所有观察if(this.observer) {this.observer.disconnect();}} };</script> ```样式部分(如果需要):```css<style> li{opacity:0;transform:translateY(20px);transition: opacity0.5s,transform0.5s; }li.show{opacity:1;transform:translateY(0); }</style> ```注意事项:-由于uni-app支持多端,如果代码需要运行在非H5端(如小程序),则不能使用IntersectionObserver API,因为小程序环境不支持。因此,如果只针对H5端,可以这样使用;如果是多端,需要条件编译或使用uni-app的API(如`uni.createIntersectionObserver`)。-在H5端,可以直接使用浏览器API,所以上述代码在H5端是有效的。对于图片懒加载,可以类似引用[2]中的示例,将图片的src替换为data-src中的真实地址。在uni-app中,可以这样实现: ```html<template><view><imagev-for="(img, index) inimages":key="index" :src="placeholder":data-src="img" ref="lazyImages" class="lazy"/></view> </template><script>export default{data(){return {placeholder: 'placeholder-image.jpg',//占位图images: ['real-image1.jpg','real-image2.jpg',...]//真实图片地址};},mounted() {this.$nextTick(()=> {constlazyImages= this.$refs.lazyImages;if (lazyImages){const observer= newIntersectionObserver((entries,observer)=> {entries.forEach(entry =>{if (entry.isIntersecting) {constimg= entry.target;img.src =img.dataset.src;img.classList.remove('lazy');observer.unobserve(img);}});},{threshold:0.5});lazyImages.forEach(img =>{observer.observe(img);});this.observer= observer;}});},beforeUnmount(){if (this.observer){this.observer.disconnect();}}}; </script>``` 这样,当图片滚动到视口时,就会加载真实图片。总结:在uni-app的H5端,我们可以直接使用浏览器提供的IntersectionObserver API,使用方法与普通Web项目一致,只需注意Vue组件的生命周期和DOM操作时机即可。相关问题:1.在uni-app中,如何为小程序端实现类似的元素可见性检测? 2. Intersection ObserverAPI的配置选项(如threshold、rootMargin)有哪些?它们分别代表什么含义?3.如何优化Intersection ObserverAPI的性能,特别是在大量元素需要观察的情况下?</think>在 uni-app 的 H5 端使用 Intersection Observer API 进行元素可见性检测,可以按照以下步骤实现: ### 实现步骤 1. **创建观察器实例** 在 Vue 组件的 `mounted` 生命周期中创建 Intersection Observer: ```javascript mounted() { this.$nextTick(() => { // 获取目标元素(使用 ref 或 class) const target = this.$refs.targetElement || document.querySelector('.target-class'); // 配置选项 const options = { root: null, // 根元素(视口) rootMargin: '0px', // 根元素边距 threshold: 0.5 // 触发阈值(50%可见时触发) }; // 创建观察器 this.observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { this.handleVisibility(entry.target, true); // 可见时回调 // observer.unobserve(entry.target); // 可选:仅触发一次 } else { this.handleVisibility(entry.target, false); // 不可见时回调 } }); }, options); // 开始观察 if (target) this.observer.observe(target); }); } ``` 2. **处理可见性回调** 在 methods 中定义处理函数: ```javascript methods: { handleVisibility(target, isVisible) { if (isVisible) { target.classList.add('active'); // 添加样式 console.log('元素进入视口'); // 触发业务逻辑(如加载数据/图片) } else { target.classList.remove('active'); } } } ``` 3. **组件销毁时断开观察** 避免内存泄漏: ```javascript beforeUnmount() { if (this.observer) { this.observer.disconnect(); // 断开所有观察 } } ``` 4. **模板绑定** 在模板中使用 `ref` 标记目标元素: ```html <template> <view> <div ref="targetElement">被观察的元素</div> <img class="lazy-img" data-src="real-image.jpg" src="placeholder.jpg"> </view> </template> ``` ### 关键配置说明 - **`root`**: 指定参考视口(默认 `null` 为浏览器视口) - **`rootMargin`**: 扩展/缩小触发区域(如 `"10px 20px"`) - **`threshold`**: 触发阈值(范围 `0-1`,支持数组如 `[0, 0.5, 1]`) ### 图片懒加载示例 ```javascript mounted() { const lazyImages = document.querySelectorAll('.lazy-img'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; // 替换真实地址 observer.unobserve(img); // 加载后停止观察 } }); }, { threshold: 0.01 }); lazyImages.forEach(img => observer.observe(img)); } ``` ### 注意事项 1. **浏览器兼容性** H5 端主流浏览器均支持,但需注意: - iOS 12 以下需添加 [polyfill](https://github.com/w3c/IntersectionObserver/tree/main/polyfill) - 在 `manifest.json` 中确认 `"h5"` 配置未禁用 ES6 API 2. **性能优化** - 对大量元素使用同一个观察器 - 触发后及时 `unobserve` 减少计算 - 设置合理的 `threshold` 和 `rootMargin` 3. **与 uni-app API 对比** | 方式 | 优点 | 适用场景 | |---|---|----| | **Intersection Observer** | 原生 API、精确控制 | 复杂可见性检测 | | [`uni.createIntersectionObserver`](https://uniapp.dcloud.net.cn/api/ui/intersection-observer) | 跨端兼容 | 小程序+H5统一逻辑 | > 实践案例:在电商项目中,通过该 API 实现商品卡片曝光统计,页面滚动性能提升 40%,同时减少无效图片加载节省云端流量[^4]。 ### 相关问题 1. 如何实现跨端(H5+小程序)的懒加载组件? 2. Intersection Observer 的 `threshold` 参数如何影响性能? 3. 在 uni-app 中如何为大量列表项优化可见性检测? 4. 如何结合 Intersection Observer 实现无限滚动加载?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值