引言

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

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

如果我们自己来实现这一系列的逻辑判断可能也不难,但是如何优雅地实现以便于更方便地使用呢?一起研究一下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函数的资料请关注Devmax其它相关文章!

vue前端框架vueuse的useScroll函数使用源码分析的更多相关文章

  1. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. 移动HTML5前端框架—MUI的使用

    这篇文章主要介绍了移动HTML5前端框架—MUI的使用的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. vue自定义加载指令v-loading占位图指令v-showimg

    这篇文章主要为大家介绍了vue自定义加载指令和v-loading占位图指令v-showimg的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. vue使用动画实现滚动表格效果

    这篇文章主要为大家详细介绍了vue使用动画实现滚动表格效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. 关于Vue 监控数组的问题

    这篇文章主要介绍了Vue 监控数组的示例,主要包括Vue 是如何追踪数据发生变化,Vue 如何更新数组以及为什么有些数组的数据变更不能被 Vue 监测到,对vue监控数组知识是面试比较常见的问题,感兴趣的朋友一起看看吧

  6. Vue子组件props从父组件接收数据并存入data

    这篇文章主要介绍了Vue子组件props从父组件接收数据并存入data的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  7. Vue h函数的使用详解

    本文主要介绍了Vue h函数的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. PHP实现的62进制转10进制,10进制转62进制函数示例

    这篇文章主要介绍了PHP实现的62进制转10进制,10进制转62进制函数,结合具体实例形式分析了php针对62进制与10进制相互转换的操作技巧,需要的朋友可以参考下

  9. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  10. vue+Element ui实现照片墙效果

    这篇文章主要为大家详细介绍了vue+Element ui实现照片墙效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部