当前位置: 首页 > news >正文

Vue3中到达可视区域后执行

项目场景:

提示:这里简述项目相关背景:

在项目中有时候需要显示一些动态效果,但是如果页面过长刷新页面的时候有些效果在没看到的时候就会执行,那么能滚动到那个区域的时候哪些动态效果就在没看到的时候就已经执行过了,那怎么才能让后滚动到可视区域的时候才执行呢?

在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>

相关文章:

  • Tauri v1 与 v2 配置对比
  • C++好用的打印日志类
  • Cangjie Magic在医疗领域的应用:智能体技术如何重塑医疗数字化
  • 科研 | 光子技术为人工智能注入新动力
  • Fiori学习专题二十五:Remote OData Service
  • 数据库设计理论:从需求分析到实现的全流程解析
  • 详解具身智能机器人开源数据集:RoboMIND
  • 潇洒郎: 100% 成功搭建Docker私有镜像仓库并管理、删除镜像
  • 偏移成像中,原始地震采集数据的数据规则化(Data Regularization)
  • Java进阶--设计模式
  • 【LeetCode Hot100】二叉树篇
  • MySQL 中 redo log、undo log 以及 bin log 的区别
  • 安全企业内部im,BeeWorks即时通讯
  • 智能 + 安全:婴幼儿托育管理实训基地标准化建设方案
  • 傅里叶与相位偏移
  • 【Java函数式编程-58.1】深入理解Java中的Consumer函数式接口
  • 基于Spring Boot + Vue 项目中引入deepseek方法
  • 基于RFID与云边端协同的智慧牧场解决方案架构设计
  • 信号完整性简介第二篇
  • 大语言模型(LLM)应用开发平台Dify详细使用
  • 2025财政观察①长三角罚没收入增速放缓,24城仍在上涨
  • 乌副总理:乌美签署矿产协议
  • 来论|受美国“保护”,日本民众要付出什么代价?
  • 陕西省通报6起违反八项规定典型问题,省卫健委原主任刘宝琴违规收受礼品礼金
  • 日菲同意扩大安全合作,外交部:反对任何在本地区拉帮结派的做法
  • 徐徕任上海浦东新区副区长,此前已任区委常委