4.7 Sensors -- useScroll

news2024/11/13 9:57:54

4.7 Sensors – useScroll

https://vueuse.org/core/useScroll/

作用

响应式的监听滚动位置和状态。

官方示例

<script setup lang="ts">
import { useScroll } from '@vueuse/core'

const el = ref<HTMLElement | null>(null)
const { x, y, isScrolling, arrivedState, directions } = useScroll(el)
</script>

<template>
  <div ref="el" />
</template>
  • 带偏移量的版本
const { x, y, isScrolling, arrivedState, directions } = useScroll(el, {
  offset: { top: 30, bottom: 30, right: 30, left: 30 },
})
  • 手动设置滚动位置
<script setup lang="ts">
import { useScroll } from '@vueuse/core'

const el = ref<HTMLElement | null>(null)
const { x, y } = useScroll(el)
</script>

<template>
  <div ref="el" />
	<!-- 手动修改滚动偏移量 -->
  <button @click="x += 10">
    Scroll right 10px
  </button>
  <button @click="y += 10">
    Scroll down 10px
  </button>
</template>
  • 平滑滚动

    设置 behavior: smooth 实现平滑滚动.。默认行为是auto ,也就是非平滑滚动。更多滚动行为,请看https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo

import { useScroll } from '@vueuse/core'

const el = ref<HTMLElement | null>(null)
const { x, y } = useScroll(el, { behavior: 'smooth' })

// Or as a `ref`:
const smooth = ref(false)
const behavior = computed(() => smooth.value ? 'smooth' : 'auto')
// 通过options传递
const { x, y } = useScroll(el, { behavior })
  • 无渲染组件代码,同样支持传递回调函数和数组
<script setup lang="ts">
import type { UseScrollReturn } from '@vueuse/core'
import { vScroll } from '@vueuse/components'

const data = ref([1, 2, 3, 4, 5, 6])

function onScroll(state: UseScrollReturn) {
  console.log(state) // {x, y, isScrolling, arrivedState, directions}
}
</script>

<template>
  <div v-scroll="onScroll">
    <div v-for="item in data" :key="item">
      {{ item }}
    </div>
  </div>

  <!-- with options -->
  <div v-scroll="[onScroll, { throttle: 10 }]">
    <div v-for="item in data" :key="item">
      {{ item }}
    </div>
  </div>
</template>

源码分析

  • 这个hook的参数比较常用,先看一下
export interface UseScrollOptions {
  /**
   * 对滚动事件进行节流,默认不节流。也就是throttle时间段内,只会触发一次
   * @default 0毫秒。
   */
  throttle?: number

  /**
   * 滚动结束后多久进行检查
   * 如果设置了throttle,这个值等于如果设置了throttle+idle
   * @default 200
   */
  idle?: number

  /**
   * left 表示距离左边距多远,arrived状态会变成true。其他方向类推。
   */
  offset?: {
    left?: number
    right?: number
    top?: number
    bottom?: number
  }

  /**
   * 滚动时触发的事件
   */
  onScroll?: (e: Event) => void

  /**
   * 滚动结束触发的事件
   */
  onStop?: (e: Event) => void

  /**
   * 滚动事件监听器的配置
   * @default {capture: false, passive: true}
   */
  eventListenerOptions?: boolean | AddEventListenerOptions

  /**
   * 平滑滚动还是立即跳转
   * @default 'auto'
   */
  behavior?: MaybeComputedRef<ScrollBehavior>
}

/**
 * 我们必须检查滚动量是否足够接近某个阈值,以便更准确地计算arrivedState。
 * 这是因为scrollTop/scrollLeft是整数的数字,而scrollHeight/scrollWidth和clienttheight /clientWidth是四舍五入的。
 * https://developer.mozilla.org/enUS/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled
 */
const ARRIVED_STATE_THRESHOLD_PIXELS = 1
  • 再看一下代码实现,大量代码都是用来定义变量的。
/**
* 代码中一些函数的定义
*/
// 1 空函数
export const noop = () => {}

// 2 防抖函数:如果多次调用,只有最后一次起作用,会在最后一次调用后,经过一段时候后触发回调。
useDebounceFn()

// 3 节流函数:如果多次调用,那么在一个时间段内,只有第一次起作用。到了下个时间段,依旧只有第一次起作用。
useThrottleFn()
export function useScroll(
  element: MaybeComputedRef<HTMLElement | SVGElement | Window | Document | null | undefined>,
  options: UseScrollOptions = {},
) {
  /**
  * 处理用户传递的参数
  */
  const {
    throttle = 0,
    idle = 200,
    onStop = noop,
    onScroll = noop,
    offset = {
      left: 0,
      right: 0,
      top: 0,
      bottom: 0,
    },
    eventListenerOptions = {
      capture: false,
      passive: true,
    },
    behavior = 'auto',
  } = options

  /**
  * x方向和y方向的偏移量。默认是0,也就是视口在页面左上角。
  */
  const internalX = ref(0)
  const internalY = ref(0)

  /**
  * 提供给外部的计算属性。当用户设置x和y的时候,要出发滚动事件。
  * 在'scrollTo()'期间,不会在进程中触发额外的'scrollTo()'。
  */
  const x = computed({
    get() {
      return internalX.value
    },
    set(x) {
      scrollTo(x, undefined)
    },
  })

  const y = computed({
    get() {
      return internalY.value
    },
    set(y) {
      scrollTo(undefined, y)
    },
  })

  /**
  * 使用 scrollTo 方法来滚动,传递目标位置的高度、左边距、滚动方式。
  */
  function scrollTo(_x: number | undefined, _y: number | undefined) {
    const _element = resolveUnref(element)

    if (!_element)
      return

    (_element instanceof Document ? document.body : _element)?.scrollTo({
      top: resolveUnref(_y) ?? y.value,
      left: resolveUnref(_x) ?? x.value,
      behavior: resolveUnref(behavior),
    })
  }

  /**
  * 是否在滚动中
  */
  const isScrolling = ref(false)
  
  /**
  * 四边的到达状态,默认左上角。
  */
  const arrivedState = reactive({
    left: true,
    right: false,
    top: true,
    bottom: false,
  })
  
  /**
  * 朝着哪个方向滚动,默认哪边都不是。
  */
  const directions = reactive({
    left: false,
    right: false,
    top: false,
    bottom: false,
  })

  /**
  * 滚动结束后,把滚动方向都设置为false。设置防抖时间:throttle + idle、
  * 同时调用用户传递的onStop
  */
  const onScrollEnd = useDebounceFn((e: Event) => {
    isScrolling.value = false
    directions.left = false
    directions.right = false
    directions.top = false
    directions.bottom = false
    onStop(e)
  }, throttle + idle)

  // ......
  // 最重要的滚动函数单独来看

  /**
  * 监听目标的scroll事件。如果发生了滚动,先看throttle的值
  * 如果设置了throttle,那么throttle的时间段内只调用一次。否则滚动即调用onScrollHandler。
  */
  useEventListener(
    element,
    'scroll',
    throttle ? useThrottleFn(onScrollHandler, throttle, true, false) : onScrollHandler,
    eventListenerOptions,
  )

  return {
    x,
    y,
    isScrolling,
    arrivedState,
    directions,
  }
}
/**
* 滚动过程中触发的函数
*/
const onScrollHandler = (e: Event) => {
  const eventTarget = (
  e.target === document ? (e.target as Document).documentElement : e.target) as HTMLElement

  const scrollLeft = eventTarget.scrollLeft
  // 如果滚动后的左边距小于原来的边距,说明时往左边滚动了。见下图1
  directions.left = scrollLeft < internalX.value
  directions.right = scrollLeft > internalY.value
  
  // 是否到达左边距。如果用户设置了offset.left,那么滚动后的左边距小于这个值就代表抵达到左边了
  arrivedState.left = scrollLeft <= 0 + (offset.left || 0)
  // 在从左往右滚动的过程中,这几个值变化如下图2
  // 可以简单理解,clientWidth是用户可见区域的宽度,scrollWidth是内容区真正的宽度。见下图3
  arrivedState.right
  = scrollLeft + eventTarget.clientWidth >= eventTarget.scrollWidth - (offset.right || 0) - ARRIVED_STATE_THRESHOLD_PIXELS
  // 实时更新滚动的距离
  internalX.value = scrollLeft

  let scrollTop = eventTarget.scrollTop

  // 移动端兼容
  if (e.target === document && !scrollTop)
  scrollTop = document.body.scrollTop

  // 上下的处理和左右是一致的
  directions.top = scrollTop < internalY.value
  directions.bottom = scrollTop > internalY.value
  arrivedState.top = scrollTop <= 0 + (offset.top || 0)
  arrivedState.bottom
  = scrollTop + eventTarget.clientHeight >= eventTarget.scrollHeight - (offset.bottom || 0) - ARRIVED_STATE_THRESHOLD_PIXELS
  internalY.value = scrollTop

  // 滚动中状态设置为true
  isScrolling.value = true
  
  // 不断触发scrollEnd事件,但是这个事件设置了防抖,只有在停顿超过throttle + idle时间后才会触发状态修改
  onScrollEnd(e)
  // 实时调用用户传递的函数
  onScroll(e)
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2114348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python系列】只更新非空的字段

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

数字电路专题:verilog 阻塞赋值和非阻塞赋值

verilog 阻塞赋值 和 非阻塞赋值 “”阻塞赋值&#xff0c; ”<”非阻塞赋值。阻塞赋值为执行完一条赋值语句&#xff0c;再执行下一条&#xff0c;可理解为顺序执行&#xff0c;而且赋值是立即执行&#xff1b; 非阻塞赋值可理解为并行执行&#xff0c;不考虑顺序&#x…

【python计算机视觉编程——7.图像搜索】

python计算机视觉编程——7.图像搜索 7.图像搜索7.1 基于内容的图像检索&#xff08;CBIR&#xff09;从文本挖掘中获取灵感——矢量空间模型&#xff08;BOW表示模型&#xff09;7.2 视觉单词**思想****特征提取**&#xff1a; 创建词汇7.3 图像索引7.3.1 建立数据库7.3.2 添加…

构建并训练卷积神经网络(CNN)对CIFAR-10数据集进行分类

深度学习实践&#xff1a;构建并训练卷积神经网络&#xff08;CNN&#xff09;对CIFAR-10数据集进行分类 引言 在计算机视觉领域中&#xff0c;CIFAR-10数据集是一个经典的基准数据集&#xff0c;广泛用于图像分类任务。本文将介绍如何使用PyTorch框架构建一个简单的卷积神经…

微信小程序uniappvue3版本-控制tabbar某一个的显示与隐藏

1. 首先在pages.json中配置tabbar信息 2. 在代码根目录下添加 tabBar 代码文件 直接把微信小程序文档里面的四个文件复制到自己项目中就可以了 3. 根据自己的需求更改index.js文件 首先我这里需要判断什么时候隐藏某一个元素&#xff0c;需要引入接口 然后在切换tabbar时&#…

git:认识git和基本操作(1)

目录 一、版本控制器 1.安装git 2.创建git本地仓库 3.配置git 二、git操作&#xff08;1&#xff09; 1.工作区、暂存区、版本库 2.添加文件 3.查看.git 4.修改文件 一、版本控制器 所谓的版本控制器&#xff0c;就是能让你了解到每一个文件的修改历史。相应的&#x…

Maven的安装

一、安装 压缩包解压完的目录如下所示&#xff08;此处为绿色免安装版&#xff09;&#xff1a; &#xff08;其余三个文件是针对Maven版本&#xff0c;第三方软件等简要介绍&#xff09; 二、环境变量 前提&#xff1a; jdk最低版本为JAVA7&#xff08;即jdk17&#xff09…

R语言统计分析——重复测量方差分析

参考资料&#xff1a;R语言实战【第2版】 所谓重复测量方差分析&#xff0c;即受试者被测量不止一次。本例使用数据集市co2数据集&#xff1a;因变量是二氧化碳吸收量&#xff08;uptake&#xff09;&#xff0c;自变量是植物类型&#xff08;Type&#xff09;和七种水平的二氧…

Gitness 基础安装

文章目录 Docker 安装注册账户创建项目导入已有仓库配置 Github Token同步源代码仓库 官方链接 Gitness was the next step in the evolution of Drone, from continuous integration to source code hosting, bringing code management and pipelines closer together. Gitnes…

自动化表格处理的革命:智能文档系统技术解析

在当今数据驱动的商业环境中&#xff0c;表格数据的自动化处理成为了企业提高效率、降低成本的关键。企业智能文档系统在智能表格识别方面展现出卓越的性能&#xff0c;通过精准识别和处理各种通用表格&#xff0c;显著提升了企业文档管理的智能化水平。本文将深入探讨该系统在…

STM32的使用方法一

注:我采用的是STM32F103RC芯片、相应的电路图和STM32CubeIDE软件这是在STM32CubeIDE软件定义芯片后&#xff0c;所给的必要的代码逻辑&#xff0c;加上了注释 #include "main.h"/* Private variables ---------------------------------------------------------*//…

Java数据结构(八)——插入排序、希尔排序

文章目录 插入排序算法介绍代码实现复杂度和稳定性 希尔排序算法介绍代码实现复杂度和稳定性 将这两种排序放在一起的原因是它们都属于 “插入”(式)排序。 还有很多排序思想&#xff0c;这里不放在一篇文章介绍是因为会导致篇幅过长&#xff0c;我们会按分类多次介绍不同的排序…

[数据集][目标检测]智慧农业草莓叶子病虫害检测数据集VOC+YOLO格式4040张9类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4040 标注数量(xml文件个数)&#xff1a;4040 标注数量(txt文件个数)&#xff1a;4040 标注…

HTTP协议 HTTPS协议 MQTT协议介绍

目录 一&#xff0e;HTTP协议 1. HTTP 协议介绍 基本介绍&#xff1a; 协议&#xff1a; 注意&#xff1a; 2. HTTP 协议的工作过程 基础术语&#xff1a; 客户端&#xff1a; 主动发起网络请求的一端 服务器&#xff1a; 被动接收网络请求的一端 请求&#xff1a; …

基于MinerU的PDF解析API

基于MinerU的PDF解析API - MinerU的GPU镜像构建 - 基于FastAPI的PDF解析接口支持一键启动&#xff0c;已经打包到镜像中&#xff0c;自带模型权重&#xff0c;支持GPU推理加速&#xff0c;GPU速度相比CPU每页解析要快几十倍不等 主要功能 删除页眉、页脚、脚注、页码等元素&…

实验记录 | 点云处理 | K-NN算法3种实现的性能比较

引言 K近邻&#xff08;K-Nearest Neighbors, KNN&#xff09;算法作为一种经典的无监督学习算法&#xff0c;在点云处理中的应用尤为广泛。它通过计算点与点之间的距离来寻找数据点的邻居&#xff0c;从而有效进行点云分类、聚类和特征提取。本菜在复现点云文章过程&#xff…

【OpenCV2.2】图像的算术与位运算(图像的加法运算、图像的减法运算、图像的融合)、OpenCV的位运算(非操作、与运算、或和异或)

1 图像的算术运算 1.1 图像的加法运算 1.2 图像的减法运算 1.3 图像的融合 2 OpenCV的位运算 2.1 非操作 2.2 与运算 2.3 或和异或 1 图像的算术运算 1.1 图像的加法运算 add opencv使用add来执行图像的加法运算 图片就是矩阵, 图片的加法运算就是矩阵的加法运算, 这就要求加…

notepad下载安装教程

一、强大高效的代码编辑器 Notepad 是一款功能强大的代码编辑器&#xff0c;专为程序员和开发人员设计。无论是编写代码、处理文本文件&#xff0c;还是进行快速编辑&#xff0c;Notepad 都能提供卓越的性能和便利的功能&#xff0c;极大提升您的工作效率。 二、安装详细教程…

双指针(5)_单调性_有效三角形的个数

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 双指针(5)_单调性_有效三角形的个数 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录…

c++stack和list 介绍

stack介绍 堆栈是一种容器适配器&#xff0c;专门设计用于在 LIFO 上下文&#xff08;后进先出&#xff09;中运行&#xff0c;其中元素仅从容器的一端插入和提取。 堆栈作为容器适配器实现&#xff0c;容器适配器是使用特定容器类的封装对象作为其基础容器 的类&#xff0c;提…