vue-infinite-scroll 源码阅读&排坑

本文详细介绍了在使用 Vue infinite scroll 库时遇到无法触发滚动事件的问题,通过阅读源码和调试,发现问题可能出在组件的 mounted 生命周期钩子。通过将 v-if 替换为 v-show 解决了问题,原因是 v-if 在元素不渲染时,相关事件绑定未执行,而 v-show 则会在初次渲染时执行。同时分享了npm包的调试经验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 场景说明

我们的前端项目中主要用第三方库vue-infinite-scroll来实现无限滚动列表。然而,在最近写一个需求时,发现基于vue-infinite-scroll来实现列表的无限滚动时,会有无法触发滚动事件的问题。这样导致了列表滚动到底部时,无法拉取新的数据。经过查阅第三方库vue-infinite-scroll的官方文档,以及参考项目中使用到此库的其他地方,发现在用法上没有什么异常。就此基于查看源码去做一个详细的研究。

  1. 源代码阅读 & 猜想
    =============

node_modules下面找到了vue-infinite-scroll库所在的地方,很幸运,打包后的代码没有压缩成完全看不懂的样子,且仅有简短的236行。这意味着我们理解代码的时间不需要太长。同时,后面我们能够直接修改打包后的文件来进行调试,验证研究中的各种猜想。

按照职能阅读: 尽管代码量不大,但以快速解决问题为目的。我们还是需要避重就轻,只阅读对解决问题有必要的部分即可。通过略读代码,根据函数名划分函数职能,可以帮助我们很好地做到这一点。

  • 简单工具类函数getScrollTopgetVisibleHeightgetElementTop等,从函数名看出它们的主要职能都是获取列表元素的一些基本属性,加以处理来实现无限滚动。而我们的bug出现在同一浏览器和网络环境中,理论上不存在因为兼容性问题导致这些函数工作异常的情况。(约100行,都可以略过)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zzkaRTMI-1656055287398)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ecc89eef1c9a470fa11bbda1fb3f5ff1~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]

  • 核心事件/属性绑定函数**doBind** : 这个函数里做了许多绑定操作,包括滑动时scroll事件的回调绑定,以及是否允许列表继续滑动,滑动距离等自定义属性的绑定操作。所以,我们的列表在滑动时,无法触发事件很有可能就是因为在这里面的绑定操作失败了。

2.png

  • 主函数: 负责把各种职能的函数组织在一起,以实现vue-infinite-scroll的功能

在根据源代码的职能进行略读之后,我们重点关注绑定函数doBind部分。在主函数中,我发现了vue-infinite-scroll是通过监听组件本身的mounted钩子来执行事件/属性的绑定的。

3.png

因此,我们作出猜想:上述遇到的无法触发滚动事件的原因,可能正正是因为监听不到/错过了组件本身的mounted生命周期钩子

3. 解决问题

调试

上文分析到,vue-infinite-scroll的代码并没有压缩得很难看,我们能够直接修改打包后的文件来进行调试。于是我们在源代码中添加一个简单的断点进行调试:不出所料, 我们的程序并没有进入这个代码块中。

4.png

那么问题定位成功了:vue-infinite-scroll的代码在运行时(监听不到/错过了)组件本身的mounted生命周期钩子,导致一系列滚动事件都无法进行绑定。或者是,组件本身的mounted钩子触发时,vue-infinite-scroll的代码仍未初始化完成。

尝试解决

有了生命周期这一线索,我最后把目光放在了一个简单的vue指令:v-if(我用了这个指令来控制列表的显隐状态)。简单地把v-if改成了v-showbug就神奇地解决了,列表再次正常滚动,并在滚动到底端的时候触发loadMore事件。

原因分析

先说说 v-showv-ifv-show 指令是通过控制元素的css属性(display)从而实现显示和隐藏的效果,这也就说无论 v-showtrue还是false,元素都会有初始渲染。v-if 就跟 v-show 不太一样了,v-if 状态改变时,是真实进行相关的DOM操作的(插入和删除),也就是说,当 v-iffalse时, 元素就不会有初始渲染。

基于上面说的,使用v-if 时:

  1. 解析到列表元素时,发现v-if="false":列表元素不进行初始渲染,doBind函数没有执行,无法进行组件mounted钩子的监听。

2.解析完成,组件挂载完毕(执行了mounted生命周期钩子),但没有被vue-infinite-scroll监听到,绑定逻辑代码没有执行。

  1. 设置v-if="true":列表元素初始渲染,vue-infinite-scroll绑定逻辑代码doBind执行,开始监听mounted生命周期钩子。但组件已完成mountedvue-infinite-scroll错过了mounted生命周期钩子,无法完成滚动等基础事件的绑定,后续滚动列表等操作无相关响应。

而在使用v-show 时:

  1. 解析到列表元素时,发现v-show="false":但列表元素依然进行初始渲染,只是通过css控制其隐藏。此时vue-infinite-scrolld对列表元素执行doBind函数,并进行组件mounted钩子的监听。

  2. 解析完成,组件挂载完毕(执行了mounted生命周期钩子),被vue-infinite-scroll监听到,执行滑动事件等相应的绑定逻辑代码。

  3. 设置v-show="true":通过css设置列表元素显示,doBind函数中滚动等基础事件的绑定早已完成,后续滚动列表等操作可以正常响应。

4. 拓展: npm包的调试

遇到第三方npm包相关的bug时,调试其代码是非常重要的一步,也做一个拓展总结,请移步 NPM包调试方式总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值