vue前端框架vueuse的useScroll函数使用源码分析

目录
  • 引言
  • 1.示例
  • 2.源码解析
    • 2.1 参数解析
    • 2.2 响应式状态定义
    • 2.3 onScrollEnd滚动结束回调
    • 2.4 onScrollHandler滚动处理
    • 2.5 使用 useEventListener监听滚动事件
    • 2.6 返回值
  • 3.总结

引言

页面很多时候都含有可滚动视图区域,可能是横向滚动也可能是纵向滚动。

  • 有时我们需要知道当前的滚动方向,是向左还是向右,是向上还是向下;
  • 有时需要知道当前是否是正在滚动,如果滚动则显示一个加载动画等;
  • 有时我们还需要知道滚动条是否已经滚动到了上下左右的边界。

如果我们自己来实现这一系列的逻辑判断可能也不难,但是如何优雅地实现以便于更方便地使用呢?一起研究一下vueuse的useScroll函数吧~

1.示例

vueuse官方文档给出了useScroll函数的demo, 我们可以在线操作看一下效果:

如上图所示,当向下滑动或者拖拽竖直方向的滚动条时则isScrolling为true表示正在向下滚动,同时useScroll能够识别出滚动方向为向下。

如上图所示,当滚动条触底的时候,useScroll能够识别出已经到达了底部。

useScroll为何如此好用,是如何实现的呢?我们一同学习其源码。

2.源码解析

先看折叠后的代码整体了解一下:

我们发现整个代码流程包括了参数的解析,状态的定义,滚动结束回调函数,滚动监听处理函数,最后是返回值,我们依次来看一下。

2.1 参数解析

const {
  throttle = 0,
  idle = 200,
  onStop = noop,
  onScroll = noop,
  offset = {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
  },
  eventListenerOptions = {
    capture: false,
    passive: true,
  },
} = options

useScroll接受两个参数,第一参数为目标元素,也就是监听哪一个元素的滚动事件;第二个参数为options,涵盖其他的选项。我们来详细地看一下这些选项的含义:

  • throttle 滚动事件的节流事件,默认不对滚动事件节流,所以throttle的默认值为0。
  • idle 滚动结束时的检查事件,这个值会和throttle 加在一起对滚动结束事件进行防抖,分析后面的代码时会看到
  • onStop 滚动结束时触发的回调函数
  • onScroll 滚动时触发的回调函数
  • offset 定义滚动条到达上下左右边界的一个偏移值,单位为像素。例如left设置为30, 则水平滚动条距离左边界30px时则认为到达了左边界。
  • eventListenerOptions 滚动事件监听器的选项

2.2 响应式状态定义

const x = ref(0)
const y = ref(0)
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,
})

定义响应式变量x用于记录上次滚动的scrollLeft的值;

y记录上次滚动的scrollTop的值;

isScrolling表示是否正在滚动。

arrivedState提供了水平方向滚动条距离左边和右边的距离以及垂直方向滚动条距离上边和下边的距离。

directions用于描述当前滚动的方向。

2.3 onScrollEnd滚动结束回调

const onScrollEnd = useDebounceFn((e: Event) => {
  isScrolling.value = false
  directions.left = false
  directions.right = false
  directions.top = false
  directions.bottom = false
  onStop(e)
}, throttle + idle)

滚动结束回调函数使用了useDebounceFn进行防抖。当滚动结束后,isScrolling赋值为false, 滚动方向全部赋值为false, 调用onStop回调。

2.4 onScrollHandler滚动处理

const onScrollHandler = (e: Event) => {
  const eventTarget = (
    e.target === document ? (e.target as Document).documentElement : e.target
  ) as HTMLElement
  const scrollLeft = eventTarget.scrollLeft
  directions.left = scrollLeft < x.value
  directions.right = scrollLeft > x.value
  arrivedState.left = scrollLeft <= 0 + (offset.left || 0)
  arrivedState.right
    = scrollLeft + eventTarget.clientWidth >= eventTarget.scrollWidth - (offset.right || 0)
  x.value = scrollLeft
  let scrollTop = eventTarget.scrollTop
  // patch for mobile compatible
  if (e.target === document && !scrollTop)
    scrollTop = document.body.scrollTop
  directions.top = scrollTop < y.value
  directions.bottom = scrollTop > y.value
  arrivedState.top = scrollTop <= 0 + (offset.top || 0)
  arrivedState.bottom
    = scrollTop + eventTarget.clientHeight >= eventTarget.scrollHeight - (offset.bottom || 0)
  y.value = scrollTop
  isScrolling.value = true
  onScrollEnd(e)
  onScroll(e)
}

onScrollHandler用于处理滚动。首先是水平方向滚动方向与是否到达左右边界的判断。说明如下:

(1)获取当前的scrollLeft和上一次的scrollLeft也就是x.value进行比较,如果scrollLeft < x.value说明向左滚动,否则向右滚动。

(2)如何判断是否到达左边界?这里考虑到了偏移量offset.left。如果当前的scrollLeft <= offset.left就认为到达了左边界。

(3)是否到达右边界要看当前滚动的距离+元素视口的宽度(clientWidth)是否大于整个内容的宽度(scrollWidth)减去偏移量的值(offset.right)

竖直方向的判断同理,不再赘述,如果您不熟悉clientWidth、scrollWidth的含义,您可以阅读笔者之前的文章:scrollTop、clientHeight、 scrollHeight...学完真的理解了。

滚动的时候还需要调用onScrollEnd触发滚动结束事件,调用onScroll回调函数,将isScrolling设置为true。

2.5 使用 useEventListener监听滚动事件

useEventListener(
  element,
  'scroll',
  throttle ? useThrottleFn(onScrollHandler, throttle) : onScrollHandler,
  eventListenerOptions,
)

使用useEventListener监听scroll事件,如果需要节流则回调函数为useThrottleFn包装过的onScrollHandler,否则直接使用onScrollHandler。

2.6 返回值

return {
  x,
  y,
  isScrolling,
  arrivedState,
  directions,
}

useScroll最后返回响应式状态。我们使用一张图总结一下这些状态:

3.总结

useScroll提供了响应式的滚动位置和状态。滚动位置包括水平方向和垂直方向的滚动位置;滚动状态包括是否在滚动,是否到达了上下左右的边界,当前滚动的方向。useScroll使用useEventListener来监听滚动事件,在滚动事件的监听回调函数中修改状态和位置。在其计算位置的源码部分我们需要了解clientWidth、scrollWidth、clientHeight、scrollHeight这些值的含义。

以上就是vueuse的useScroll函数源码分析的详细内容,更多关于vueuse useScroll函数的资料请关注我们其它相关文章!

(0)

相关推荐

  • 一文快速详解前端框架 Vue 最强大的功能

    组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.一般来说,组件可以有以下几种关系: 如上图所示,A 和 B.B 和 C.B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代). 针对不同的使用场景,如何选择行之有效的通信方式?这是我们所要探讨的主题.本文总结了vue组件间通信的几种方式,如props. $emit/ $on.vuex. $parent / $children. $attrs/ $lis

  • 5个可以加速开发的VueUse函数库(小结)

    目录 VueUse 有哪些实用程序? 将 VueUse 安装到你的 Vue 项目中 1.useRefHistory 跟踪响应式数据的更改 2.onClickOutside 关闭模态 3.useVModel 简化了 v-model 绑定 4.使用InterpObserver 跟踪元素可见性 5.useTransition 在值之间缓和 最后的想法 VueUse 是 Anthony Fu 的一个开源项目,它为 Vue 开发人员提供了大量适用于 Vue 2 和 Vue 3 的基本 Compositio

  • Vue新玩具VueUse的具体用法

    目录 前言 什么是 VueUse 简单上手 还有我们熟悉的 防抖 和 节流 还还有全局状态共享的函数 更多 前言 上次在看前端早早聊大会中, 尤大大再一次提到了 VueUse 的一个库. 好奇了一下,点看看了看.好家伙啊, 我直接好家伙.这不就是曾经我也想自己写一个  vue 版的 hooks 库吗?(因为我觉得 vue3 和 hooks 太像了) 可是我还不太会, 你现在直接把我的梦想给破灭了,下面我们一起来看看吧!VueUse 作者 Anthony Fu 分享可组合的 Vue_哔哩哔哩_bi

  • VueUse功能精简你的dependencies

    目录 引言 使用前安装 网页全屏 剪切板 取色器 拖拽元素 本地缓存 其他 安全区域 动态修改favicon 引言 VueUse是一个基于Composition API的实用函数集合,支持Vue2和Vue3,使用它可以帮助我们快速实现日常开发中一些常见的需求.本文将分享列举几个常见的需求来通过VueUse实现,让大家感受其魅力! 使用前安装 Vue3: npm i @vueuse/core --save Vue2 的话还需要额外安装 @vue/composition-api npm i @vue

  • VueUse使用及造轮子选择对比示例详解

    目录 前言 ‍ 问题 ‍♂️ 解决 更多 前言 想想一名React开发开发Vue是什么体验.就在今天初含泪写多一个vue项目,不是转,是写多!选用的是vue3+vite开发.Composition API 让我得心应手. 之前react开发选的是react16,ahooks是我接触最多的hooks库了,很贴合我的业务.在使用vue3的时候开发的时候选取了 vueuse . ‍ 问题 在前端开发中和请求打交道是最多的,大多数业务都是restful api架构,我们拿到数据做处理,当前流行的框架配备

  • 前端框架Vue父子组件数据双向绑定的实现

    目录 一.父子组件单向传值 1.父向子传值 2.子向父传值 二.父子组件数据双向绑定 实现思路: 父 向 子 组件传值:使用 props 属性.( props 是property[属性] 的复数简写 ) 子 向 父 组件传值:使用自定义事件. 一.父子组件单向传值 1.父向子传值 父向子组件传值,子组件接收到数据之后,保存到自己的变量中. //父组件写法 <cld :numP="num" ></cld> //子组件定义以及数据 components:{ cld:

  • Vue3+vueuse实现放大镜示例详解

    目录 前言 准备工作 功能实现 完整实现代码 结束语 前言 给大家带来一种潮流的方式,实现放大镜效果,安排

  • vue前端框架vueuse的useScroll函数使用源码分析

    目录 引言 1.示例 2.源码解析 2.1 参数解析 2.2 响应式状态定义 2.3 onScrollEnd滚动结束回调 2.4 onScrollHandler滚动处理 2.5 使用 useEventListener监听滚动事件 2.6 返回值 3.总结 引言 页面很多时候都含有可滚动视图区域,可能是横向滚动也可能是纵向滚动. 有时我们需要知道当前的滚动方向,是向左还是向右,是向上还是向下: 有时需要知道当前是否是正在滚动,如果滚动则显示一个加载动画等: 有时我们还需要知道滚动条是否已经滚动到了

  • vue前端框架—Mint UI详解(更适用于移动端)

    一.mintUI简介 mint是一个基于vue的前端UI框架,而它的样式比较类似于手机的样式,可以说是一个基于vue打包app的UI框架,使用mint框架可以给使用vue打包的app的用户更好的交互体验.mint已支持vue2.0. 二.安装和引入mintUI     在安装之前首先要对vue.js有所了解,有一个建立好的vue的项目以及安装好的node.js. 执行命令npm i mint-ui -S,出现以下界面代表安装成功. 引入muitUI: 在main.js中加入 import Min

  • Vue前端框架搭建过程

    目录 一.安装 NodeJS 二.安装 vue-cli 三.创建项目 一.安装 NodeJS 见 Windows下安装NodeJS. 二.安装 vue-cli 1.vue-cli 2.x 升级到 3.x (1)卸载 2.x 版本 npm uninstall -g vue-cli (2)安装 npm install -g @vue/cli (3)查看版本 vue -V vue -V@vue/cli 5.0.8 三.创建项目 1.vue-cli 2.x 项目 (1)创建 vue init webpa

  • 浅析vue 函数配置项watch及函数 $watch 源码分享

    Vue双向榜单的原理 大家都知道Vue采用的是MVVM的设计模式,采用数据驱动实现双向绑定,不明白双向绑定原理的需要先补充双向绑定的知识,在watch的处理中将运用到Vue的双向榜单原理,所以再次回顾一下: Vue的数据通过Object.defineProperty设置对象的get和set实现对象属性的获取,vue的data下的数据对应唯一 一个dep对象,dep对象会存储改属性对应的watcher,在获取数据(get)的时候为相关属性添加具有对应处理函数的watcher,在设置属性的时候,触发

  • Vue 中 template 有且只能一个 root的原因解析(源码分析)

    引言 今年, 疫情 并没有影响到各种面经的正常出现,可谓是络绎不绝(学不动...).然后,在前段时间也看到一个这样的关于 Vue 的问题, 为什么每个组件 template 中有且只能一个 root? 可能,大家在平常开发中,用的较多就是 template 写 html 的形式.当然,不排除用 JSX 和 render() 函数的.但是,究其本质,它们最终都会转化成 render() 函数.然后,再由 render() 函数转为 Vritual DOM (以下统称 VNode ).而 rende

  • VUE+Element实现增删改查的示例源码

    前言 &最近因为一些原因,没有更博客,昨天老师布置了一个作业,用vue实现增删改查功能,想想这也不难,就做一下试试吧. 因为自己写的样式没有别人做的好,因此我想用现成的UI框架,一直也没用过Element,就干脆趁机学一下吧. 实验步骤 首先引入一下element的css以及js <!-- 引入样式 --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chal

  • vue 虚拟dom的patch源码分析

    本文介绍了vue 虚拟dom的patch源码分析,分享给大家,具体如下: 源码目录:src/core/vdom/patch.js function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) { let oldStartIdx = 0 let newStartIdx = 0 let oldEndIdx = oldCh.length - 1 let oldStartVnode = oldCh[0]

  • Vue 源码分析之 Observer实现过程

    导语: 本文是对 Vue 官方文档深入响应式原理(https://cn.vuejs.org/v2/guide/reactivity.html)的理解,并通过源码还原实现过程. 响应式原理可分为两步,依赖收集的过程与触发-重新渲染的过程.依赖收集的过程,有三个很重要的类,分别是 Watcher.Dep.Observer.本文主要解读 Observer . 这篇文章讲解上篇文章没有覆盖到的 Observer 部分的内容,还是先看官网这张图: Observer 最主要的作用就是实现了上图中touch

  • Vue.js源码分析之自定义指令详解

    前言 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令. 官网介绍的比较抽象,显得很高大上,我个人对自定义指令的理解是:当自定义指令作用在一些DOM元素或组件上时,该元素在初次渲染.插入到父节点.更新.解绑时可以执行一些特定的操作(钩子函数() 自定义指令有两种注册方式,一种是全局注册,使用Vue.directive(指令名,配置参数)注册,注册之后所有的Vue实例都可以使用,另一种是局部注册,在创建Vue实例时通过directives属性创建局部指

  • Vue源码分析之虚拟DOM详解

    为什么需要虚拟dom? 虚拟DOM就是为了解决浏览器性能问题而被设计出来的.例如,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量.简单来说,可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag).属性(attrs)和子元素对象( children)三个属性. ----- 元素节点: 元素节点更贴近于我们

随机推荐