mp 和 web 的标准差异:
- mp 不会考虑 container 关系
- web 必须是 container 关系才会计算交叉
mp 和 web 的代码示例如下:
web/w3c 标准:
<!DOCTYPE html>
<!--https://html.onlineviewer.net/-->
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>非空 Root IntersectionObserver 极简示例</title>
<style>
body { margin: 0; padding: 0;
border: 5px solid;
font-size: 20px;
font-weight: bold;
}
/* 1. Root 容器样式 */
#container {
width: 300px;
height: 300px;
margin: 50px auto; /* 居中 */
border: 5px solid blue;
overflow: scroll; /* 关键:使内容可滚动,模拟裁剪效果 */
background-color: #f0f8ff;
position: relative;
}
/* 2. 占位符样式,确保容器内有滚动内容 */
#spacer {
height: 500px;
background-color: yellow;
/* 将目标元素放在底部 */
margin-top: 200px;
}
/* 3. Target 元素样式 */
#target {
width: 100%;
height: 100px;
background-color: red;
color: white;
text-align: center;
line-height: 100px;
/* target 元素位于 container 内部,但比 container 底部低 */
position: absolute;
bottom: -100px;
}
#fixed {
left: 25px;
right: 25px;
top: 100px;
height: 100px;
border: 5px solid red;
position: fixed;
z-index: 2;
}
</style>
</head>
<body>
<div id="fixed"></div>
<div id="ratio">ratio</div>
<div id="ratio2">ratio</div>
<div id="container">
<div id="target">被观察的目标</div>
<div id="spacer">滚动占位区域</div>
</div>
<script>
// 1. 获取 Root 和 Target 元素
const rootElement = document.getElementById('container');
const targetElement = document.getElementById('target');
const fixedElement = document.getElementById('fixed');
const ratioElement = document.getElementById('ratio');
const ratioElement2 = document.getElementById('ratio2');
// 2. 配置选项:使用 #container 作为 Root,并定义阈值
const options = {
root: rootElement,
rootMargin: '0px',
threshold: Array.from({length: 101}, (_, i) => i / 100)
};
const options2 = {
root: targetElement,
rootMargin: '0px',
threshold: Array.from({length: 101}, (_, i) => i / 100)
};
// 3. 定义回调函数
const callback = (entries, observer) => {
entries.forEach(entry => {
const ratio = entry.intersectionRatio.toFixed(2);
console.log(`[IO] Target: ${entry.target.id}, Ratio: ${ratio}, isIntersecting: ${entry.isIntersecting}`);
// 实时更新 Target 元素的文本
ratioElement.textContent = `交集比例: ${ratio}`;
});
};
const callback2 = (entries, observer) => {
entries.forEach(entry => {
const ratio = entry.intersectionRatio.toFixed(2);
console.log(`[IO] Target: ${entry.target.id}, Ratio: ${ratio}, isIntersecting: ${entry.isIntersecting}`);
// 实时更新 Target 元素的文本
ratioElement2.textContent = `交集比例: ${ratio}`;
});
};
// 4. 创建并启动观察者
if (rootElement && targetElement) {
const observer = new IntersectionObserver(callback, options);
// 观察目标元素
observer.observe(targetElement);
}
if (fixedElement && targetElement) {
const observer2 = new IntersectionObserver(callback2, options2);
// 观察目标元素
observer2.observe(fixedElement);
}
</script>
</body>
</html>
小程序标准:
JS
Page({
data: {
ratio: 'ratio',
ratio2: 'ratio2'
},
onReady() {
// 1. 创建第一个 IntersectionObserver,以 #container 作为参照区域
this.observer1 = this.createIntersectionObserver({
thresholds: Array.from({ length: 101 }, (_, i) => i / 100)
});
this.observer1.relativeTo('#container').observe('#target', (res) => {
// 在小程序中,res.intersectionRatio 是交集比例
const ratio = res.intersectionRatio.toFixed(2);
console.log(`[IO1] Target: #target, Root: #container, Ratio: ${ratio}`);
this.setData({
ratio: `被观察目标与蓝框的交叉比例: ${ratio}`
});
});
// 2. 创建第二个 IntersectionObserver,以 #target 作为参照区域
this.observer2 = this.createIntersectionObserver({
thresholds: Array.from({ length: 101 }, (_, i) => i / 100)
});
this.observer2.relativeTo('#target').observe('#fixed', (res) => {
const ratio = res.intersectionRatio.toFixed(2);
console.log(`[IO2] Target: #fixed, Root: #target, Ratio: ${ratio}`);
this.setData({
ratio2: `被观察目标与红框的交叉比例: ${ratio}`
});
});
},
onUnload() {
// 页面卸载时停止所有监听
if (this.observer1) {
this.observer1.disconnect();
}
if (this.observer2) {
this.observer2.disconnect();
}
}
});
CSS
page {
border: 5rpx solid;
font-size: 40rpx;
font-weight: bold;
}
#container {
width: 600rpx;
height: 600rpx;
margin: 100rpx auto;
border: 5rpx solid blue;
background-color: #f0f8ff;
position: relative;
}
#spacer {
height: 1000rpx;
width: 100%;
background-color: yellow;
margin-top: 400rpx;
}
#target {
width: 100%;
height: 200rpx;
background-color: red;
color: white;
text-align: center;
line-height: 200rpx;
position: absolute;
bottom: -200rpx;
}
#fixed {
left: 50rpx;
right: 50rpx;
top: 200rpx;
height: 200rpx;
width: 650rpx;
border: 5rpx solid red;
position: fixed;
z-index: 2;
}
#ratio, #ratio2 {
font-size: 30rpx;
position: fixed;
z-index: 3;
left: 10rpx;
top: 10rpx;
}
#ratio2 {
top: 50rpx;
}
XML
<view id="fixed"></view>
<view id="ratio">{{ratio}}</view>
<view id="ratio2">{{ratio2}}</view>
<scroll-view id="container" scroll-y="{{true}}">
<view id="target">被观察的目标</view>
<view id="spacer">滚动占位区域</view>
</scroll-view>
