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

Vue3组合式函数(滚动监测 useScroll)

主要用于实时监测目标元素滚动位置及状态

工具函数源码

/**
 * 组合式函数
 * 实时监测目标元素滚动位置及状态
 *
 * 自定义钩子用于处理滚动事件和状态
 * @param target 滚动目标元素,可以是 Ref、HTMLElement、Window 或 Document,默认为 window
 * @param throttleDelay 节流延迟,用于限制滚动事件的触发频率,默认为 0
 * @param onScroll 滚动事件的回调函数,可选
 * @param onStop 滚动结束的回调函数,可选
 * @returns 返回一个对象,包含滚动位置和各种状态信息
 */
import { ref, computed, watch, onBeforeUnmount } from 'vue'
import type { Ref } from 'vue'
import { throttle, debounce } from 'vue-amazing-ui'
export function useScroll(
  target: Ref | HTMLElement | Window | Document = window,
  throttleDelay: number = 0,
  onScroll?: (e: Event) => void,
  onStop?: (e: Event) => void
) {
  const x = ref(0) // 水平滚动距离
  const xScrollMax = ref(0) // 水平最大可滚动距离
  const y = ref(0) // 垂直滚动距离
  const yScrollMax = ref(0) // 垂直最大可滚动距离
  const isScrolling = ref(false) // 是否正在滚动
  const left = ref(false) // 是否向左滚动
  const right = ref(false) // 是否向右滚动
  const top = ref(false) // 是否向上滚动
  const bottom = ref(false) // 是否向下滚动
  const lastScrollLeft = ref(0) // 上一次水平滚动距离
  const lastScrollTop = ref(0) // 上一次垂直滚动距离
  // 滚动事件
  function scrollEvent(e: Event) {
    isScrolling.value = true
    const eventTarget = ((e.target as Document).documentElement ?? e.target) as HTMLElement
    x.value = eventTarget.scrollLeft
    y.value = eventTarget.scrollTop
    left.value = x.value < lastScrollLeft.value
    right.value = x.value > lastScrollLeft.value
    top.value = y.value < lastScrollTop.value
    bottom.value = y.value > lastScrollTop.value
    lastScrollLeft.value = x.value
    lastScrollTop.value = y.value
    debounceScrollEnd(e)
    onScroll && onScroll(e)
  }
  // 使用节流函数限制滚动事件触发频率
  const throttleScroll = throttle(scrollEvent, throttleDelay)
  // 滚动结束事件
  function scrollEndEvent(e: Event) {
    if (!isScrolling.value) {
      return
    }
    isScrolling.value = false
    left.value = false
    right.value = false
    top.value = false
    bottom.value = false
    onStop && onStop(e)
  }
  // 使用防抖函数延迟处理滚动结束事件
  const debounceScrollEnd = debounce(scrollEndEvent, throttleDelay + 200)
  // 计算滚动目标元素
  const scrollTarget = computed(() => {
    const targetValue = toValue(target)
    if (targetValue) {
      return targetValue
    }
    return null
  })
  // 监听滚动目标元素的变化
  watch(
    () => scrollTarget.value,
    (to: any, from: any) => {
      if (from) {
        cleanup(from)
      }
      if (to) {
        const el: Element = ((to as Window)?.document?.documentElement ||
          (to as Document)?.documentElement ||
          (to as HTMLElement)) as Element
        xScrollMax.value = el.scrollWidth - el.clientWidth
        yScrollMax.value = el.scrollHeight - el.clientHeight
        el.addEventListener('scroll', throttleScroll)
        el.addEventListener('scrollend', debounceScrollEnd)
      }
    },
    {
      immediate: true,
      flush: 'post'
    }
  )
  // 清理函数,用于移除事件监听器
  function cleanup(target: any) {
    const el: Element = ((target as Window)?.document?.documentElement ||
          (target as Document)?.documentElement ||
          (target as HTMLElement)) as Element
    el.removeEventListener('scroll', throttleScroll)
    el.removeEventListener('scrollend', debounceScrollEnd)
  }
  // 在组件卸载前调用清理函数
  onBeforeUnmount(() => cleanup(scrollTarget.value))
  // 返回滚动位置和各种状态信息
  return { x, xScrollMax, y, yScrollMax, isScrolling, left, right, top, bottom }
}

效果如下图

在这里插入图片描述

在线预览

基本使用

<script setup lang="ts">
import { ref } from 'vue'
import { useScroll } from 'vue-amazing-ui'
const scrollRef = ref()
const { x, xScrollMax, y, yScrollMax, isScrolling, left, right, top, bottom } = useScroll(scrollRef, 0, onScroll, onStop)
function onScroll(e: Event) {
  console.log('scroll', e)
}
function onStop(e: Event) {
  console.log('scrollend', e)
}
</script>
<template>
  <Flex justify="space-between">
    <div class="scroll-container" ref="scrollRef" >
      <div class="scroll-content">
        <div class="inside-content">Scroll Me</div>
      </div>
    </div>
    <Card title="滚动位置及状态" :body-style="{ fontSize: '16px' }">
      <p>水平滚动距离:{{ x }}</p>
      <p>垂直滚动距离:{{ y }}</p>
      <p>水平最大可滚动距离:{{ xScrollMax }}</p>
      <p>垂直最大可滚动距离:{{ yScrollMax }}</p>
      <p>是否正在滚动:{{ isScrolling }}</p>
      <p>是否向左滚动:{{ left }}</p>
      <p>是否向右滚动:{{ right }}</p>
      <p>是否向上滚动:{{ top }}</p>
      <p>是否向下滚动:{{ bottom }}</p>
    </Card>
  </Flex>
</template>
<style lang="less" scoped>
.scroll-container {
  width: 360px;
  height: 360px;
  border-radius: 12px;
  border: 2px solid #1677ff;
  overflow: scroll;
  .scroll-content {
    position: relative;
    width: 600px;
    height: 600px;
    .inside-content {
      position: absolute;
      top: 33.3%;
      left: 33.3%;
      font-size: 20px;
      color: rgba(0, 0, 0, 0.88);
      font-weight: 500;
      background: #fafafa;
      padding: 6px 8px;
      border-radius: 8px;
    }
  }
}
</style>

Params

参数说明类型默认值
target滚动目标元素Ref | HTMLElement | Window | Documentwindow
throttleDelay节流延迟时间,单位 ms,用于限制滚动事件的触发频率number0
onScroll?滚动事件的回调函数(e: Event) => voidundefined
onStop?滚动结束的回调函数(e: Event) => voidundefined

相关文章:

  • 配置银河麒麟V10高级服务器操作系统安装vmware tools。在您的计算机上尚未找到用于此虚拟机的 VMwareTools。安装将无法继续。
  • Java 大视界 -- 基于 Java 的大数据分布式存储系统的数据备份与恢复策略(139)
  • Qt 关键技术点总结与实践经验
  • docker登陆问题
  • Docker启动mysql容器并绑定卷,容器自动退出
  • Java JAR包的`META-INF`目录下可以放置多种配置文件的整理
  • es-将知识库中的数据转换为向量存储到es并进行相似性检索
  • 科普类——双目立体视觉与 RGBD 相机的简单对比
  • Qt按钮控件常用的API
  • qt 线程
  • Redis数据类型与场景应用解析
  • DeepSeek 3FS 与 JuiceFS:架构与特性比较
  • C++优先级队列priority_queue、仿函数
  • 【java面向对象进阶】------继承
  • [动手学习深度学习]26. 网络中的网络 NiN
  • 个人blog系统 前后端分离 前端js后端go
  • 【保姆级教程】Windows系统+ollama+Docker+Anythingllm部署deepseek本地知识库问答大模型,可局域网多用户访问
  • 深度学习框架PyTorch——从入门到精通(5)构建神经网络
  • 华为OD机试 - 最长回文字符串 - 贪心算法(Java 2024 E卷 100分)
  • 算法 之 ST表
  • 一季度我国服务进出口总额19741.8亿元,同比增长8.7%
  • “85后”潘欢欢已任河南中豫融资担保有限公司总经理
  • “自己生病却让别人吃药”——抹黑中国经济解决不了美国自身问题
  • 国内生产、境外“游一圈”再进保税仓,这些“全球购”保健品竟是假进口
  • 理想汽车副总裁刘杰:不要被竞争牵着鼻子走,也不迷信护城河
  • 江苏、安徽跨省联动共治“样板间”:进一扇门可办两省事