baimacms/test.vue

151 lines
3.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="test-page">
<view class="desc-card">
<text class="title">IntersectionObserver 仅首次触发演示</text>
<text class="subtitle">向下滚动观察各模块首次进入视口时的淡入效果</text>
</view>
<view class="section-title">场景仅首次触发 视口内淡入动画</view>
<view
class="fade-box"
v-for="(item, index) in fadeList"
:key="index"
:id="`fade-${index}`"
:class="{ 'fade-in': item.visible }"
>
<text class="box-text">模块 {{ index + 1 }}</text>
<text class="box-status">{{ item.triggered ? '✅ 已触发(不再重复)' : '⏳ 等待首次进入视口...' }}</text>
</view>
<view class="footer-space"></view>
</view>
</template>
<script>
export default {
data() {
return {
fadeList: Array.from({ length: 10 }, () => ({
visible: false,
triggered: false
})),
// ⭐ 关键:用一个数组存放每个元素独立的 observer避免互相覆盖
observers: []
}
},
onReady() {
this.initFadeObserver();
},
onUnload() {
// 页面卸载时,断开所有 observer
this.observers.forEach(obs => obs.disconnect());
},
methods: {
initFadeObserver() {
this.fadeList.forEach((_, index) => {
// ⭐ 核心修复:每个元素创建独立的 IntersectionObserver 实例
// 同一个实例多次调用 observe() 会被覆盖,只有最后一个生效
const observer = uni.createIntersectionObserver(this, {
thresholds: [0]
});
observer.relativeToViewport();
observer.observe(`#fade-${index}`, (result) => {
const item = this.fadeList[index];
// 进入视口 且 之前没触发过
if (result.intersectionRatio > 0 && !item.triggered) {
console.log(`模块 ${index + 1} 首次进入视口`);
this.$set(this.fadeList, index, {
visible: true,
triggered: true
});
// 触发后断开这个 observer彻底释放
observer.disconnect();
}
});
// 保存到数组,方便 onUnload 统一清理
this.observers.push(observer);
});
}
}
}
</script>
<style scoped>
.test-page {
background-color: #f5f6f8;
padding: 30rpx;
}
.desc-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 24rpx;
padding: 40rpx;
margin-bottom: 40rpx;
}
.title {
color: #ffffff;
font-size: 40rpx;
font-weight: bold;
display: block;
}
.subtitle {
color: rgba(255, 255, 255, 0.85);
font-size: 26rpx;
margin-top: 16rpx;
display: block;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin: 40rpx 0 20rpx;
padding-left: 20rpx;
border-left: 8rpx solid #ff416c;
}
.fade-box {
height: 240rpx;
background: #ffffff;
border-radius: 20rpx;
margin-bottom: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
opacity: 0;
transform: translateY(60rpx);
transition: all 0.6s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.fade-box.fade-in {
opacity: 1;
transform: translateY(0);
}
.box-text {
font-size: 36rpx;
color: #333;
font-weight: bold;
}
.box-status {
font-size: 24rpx;
color: #999;
margin-top: 12rpx;
}
.footer-space {
height: 100rpx;
}
</style>