项目场景:
提示:这里简述项目相关背景:
在项目中有时候需要显示一些动态效果,但是如果页面过长刷新页面的时候有些效果在没看到的时候就会执行,那么能滚动到那个区域的时候哪些动态效果就在没看到的时候就已经执行过了,那怎么才能让后滚动到可视区域的时候才执行呢?
在Vue 3中,要判断一个元素是否到达可视区域,你可以使用几种不同的方法。最常见和直接的方法是利用Intersection Observer API
Intersection Observer是一个非常强大的API,可以自动“观察”目标元素是否进入其祖先元素或顶级文档视口的可见区域。
到达可视区域的时候就会执行
分析:
提示:这里填写问题的分析:
首先需要时vue3项目,另外,要在onMounted钩子函数中作操作
基本操作如下
1:使用Intersection Observer
<template>
<div ref="observerElement" class="observed-element">
我是需要观察的元素
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const observerElement = ref(null);
onMounted(() => {
const options = {
root: null, // 使用视口作为参照点
rootMargin: '0px',
threshold: 0.1 // 元素10%在视口内时触发回调
};
const callback = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('元素进入了视口!');
} else {
console.log('元素离开了视口。');
}
});
};
const observer = new IntersectionObserver(callback, options);
if (observerElement.value) {
observer.observe(observerElement.value);
}
});
</script>
2:计算元素位置与视口的关系
如果你不希望使用Intersection Observer API,你可以通过计算元素的位置来判断它是否进入视口。这通常涉及到获取元素的位置和视口的高度。
<template>
<div ref="element" class="observed-element">我是需要观察的元素</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const element = ref(null);
onMounted(() => {
const checkVisibility = () => {
if (!element.value) return;
const rect = element.value.getBoundingClientRect();
const isVisible = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom
<=
(window.innerHeight || document.documentElement.clientHeight) &&
rect.right
<=
(window.innerWidth || document.documentElement.clientWidth)
);
if (isVisible) {
console.log('元素进入了视口!');
} else {
console.log('元素离开了视口。');
}
};
checkVisibility(); // 初始检查一次
// 添加滚动事件监听器以持续检查
window.addEventListener('scroll', checkVisibility);
// 添加窗口大小改变事件监听器以持续检查
window.addEventListener('resize', checkVisibility);
});
</script>
方案实例:
提示:这里填写该问题的具体解决方案:
在组件中使用这个方法直接在子组件中使用不需要再父组件中操作
如下:
父组件:
<!-- 使用子组件 -->
<bannerGreen
:bannerInfo="bannerInfo"/>
//引入子组件
import bannerGreen from '@/view/Home/components/bannerGreen.vue';
子组件
<template>
<div
ref="observerElement"
class="observed-element flexEv bannerBg padTB100 padLR65 colorW">
<div class="flex" v-for="item in props.bannerInfo">
<div class="borderR paddingR20 flexC">
<i
:class="item.icon"
class="iconfont fontS40 fontW4 colorW hoverS"></i>
</div>
<div class="paddingL20">
<div
ref="numRef"
class="fontS26 fontW6 marginB10 number inLb"
:data-target="item.textTop"></div>
<div class="fontS26 fontW6 inLb">+</div>
<div class="fontS18 fontW5">{{item.textBottom}}</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import {
reactive,
toRefs,
ref,
Ref,
PropType,
onMounted,
onBeforeUnmount,
} from "vue"
const props=defineProps({
//
bannerInfo:{
type:Array
},
})
// 自动将数值加到会后那个值的方法
const changeNum=()=>{
// 获取元素
const numbers = document.querySelectorAll('.number')
console.log("",numbers)
// 获取所有的dom,querySelectorAll为为数组
numbers.forEach(item => {
item.textContent = "0";
const upDateNumber = () => {
// 获取每个类名为number的data-target,即获取最大值
const target = Number(item.getAttribute('data-target'))
// 获取当前div的数值
const d = Number(item.textContent)
// 设置数据增加的值,可以通过target除的数值确定怎么加数值的快慢
const increment = target / 100
// 当数字小于最大值时,执行下面的操作
if (d < target) {
// 向上取整
item.textContent = `${Math.ceil(d + increment)}`
// 1ms重新调用,不然它会在第一次运行完就结束
setTimeout(upDateNumber, 10)
} else {
item.textContent = target+"";//textContent的值是 字符串 所以加个空字符
}
}
upDateNumber()
})
}
onMounted(()=>{
console.log()
})
// ================================到达可视区域的方法
const observerElement = ref(null);
onMounted(() => {
const options = {
root: null, // 使用视口作为参照点
rootMargin: '0px',
threshold: 0.1 // 元素10%在视口内时触发回调
};
const callback = (entries:any, observer:any) => {
entries.forEach((entry:any) => {
if (entry.isIntersecting) {
console.log('元素进入了视口!');
//到达可视区域 执行 数字自增的方法
changeNum()
} else {
console.log('元素离开了视口。');
}
});
};
const observer = new IntersectionObserver(callback, options);
if (observerElement.value) {
observer.observe(observerElement.value);
}
});
onBeforeUnmount(()=>{
console.log()
})
const emit =defineEmits([
""
])
</script>
<style lang="less" scoped>
.bannerBg{
background-color:#1d7b51 ;
}
.borderR{
border-right: 1px solid #ffffff;
}
</style>