vant4 源码
文章描述
本文为稀土掘金技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!
1. 前言
大家好,我是 若川。我倾力持续组织了一年 每周大家一起学习200行左右的源码共读活动,感兴趣的可以 点此扫码加我微信 ruochuan12 参与。另外,想学源码,极力推荐关注我写的专栏 《学习源码整体架构系列》,目前是掘金关注人数(4.1k+ 人)第一的专栏,写有 20 余篇源码文章。
我们开发业务时经常会使用到组件库,一般来说,很多时候我们不需要关心内部实现。但是如果希望学习和深究里面的原理,这时我们可以分析自己使用的组件库实现。有哪些优雅实现、最佳实践、前沿技术等都可以值得我们借鉴。
相比于原生 JS 等源码。我们或许更应该学习,正在使用的组件库的源码,因为有助于帮助我们写业务和写自己的组件。
如果是 Vue 技术栈,开发移动端的项目,大多会选用 vant 组件库,目前(2022-11-13) star 多达 20.4k。我们可以挑选 vant 组件库学习,我会写一个 组件库源码系列专栏,欢迎大家关注。
学完本文,你将学到:
1. 学会如何用 vue3 + ts 开发一个 List 组件
2. 学会封装各种组合式 `API`
3. 等等2. 准备工作
看一个开源项目,第一步应该是先看 README.md 再看贡献文档 github/CONTRIBUTING.md。
2.1 克隆源码 && 跑起来
You will need Node.js >= 14 and pnpm.
我们先来看 pnpm dev 最终执行的什么命令。
vant 项目使用的是 monorepo 结构。查看根路径下的 package.json。
vant/package.json => "dev": "pnpm --dir ./packages/vant dev" vant/packages/vant/package.json => "dev": "vant-cli dev"
pnpm dev 最终执行的是:vant-cli dev 执行测试用例。本文主要是学习 List 组件 的实现,所以我们就不深入 vant-cli dev 命令了。
3. List 组件
瀑布流滚动加载,用于展示长列表,当列表即将滚动到底部时,会触发事件并加载更多列表项。
从这个描述和我们自己体验 demo 来。 至少有以下三个问题值得去了解学习。
如何监听滚动
如何计算滚动到了底部
如何触发事件加载更多
带着问题我们直接找到 list demo 文件:vant/packages/vant/src/list/demo/index.vue。为什么是这个文件,我在上篇文章 跟着 vant4 源码学习如何用 vue3+ts 开发一个 loading 组件,仅88行代码 分析了其原理,感兴趣的小伙伴点击查看。这里就不赘述了。
3.1 利用 demo 调试
组件源码中的 TS 代码我不会过多解释。没学过 TS 的小伙伴,推荐学这个 TypeScript 入门教程。 另外,vant 使用了 @vue/babel-plugin-jsx 插件来支持 JSX、TSX。
4. 入口文件
主要就是导出一下类型和变量等。
withInstall 函数在上篇文章 5.1 withInstall 给组件对象添加 install 方法 也有分析,这里就不赘述了。
我们可以在这些文件,任意位置加上 debugger 调试源码。
5. 主文件
debugger 调试截图。

接着我们来看其他一些事件。
5.1 一些事件 useExpose、useEventListener
由上面代码可以看出,check 函数非常重要,我们在下文分析它。
我们先分析上面代码用到的 useExpose、useEventListener 组合式 API。
5.2 useExpose 暴露
通过 ref 可以获取到 List 实例并调用实例方法,详见 组件实例方法。
Vant中的许多组件提供了实例方法,调用实例方法时,我们需要通过ref来注册组件引用信息,引用信息将会注册在父组件的$refs对象上。注册完成后,我们可以通过this.$refs.xxx访问到对应的组件实例,并调用上面的实例方法。
5.3 useEventListener 绑定事件
方便地进行事件绑定,在组件 mounted 和 activated 时绑定事件,unmounted 和 deactivated 时解绑事件。

6. steup check 函数
从 check 函数可以看出,主要就是利用滚动高度,接下来我们看这个函数中,使用到的组合式 API,useTabStatus、useScrollParent、useRect。
6.1 useTabStatus tab 组件的状态
代码根据 commit 可以发现 useTabStatus 有这样一次提交。
fix(List): skip check when inside an inactive tab
主要是在 van-tabs 组件中,provide(TAB_STATUS_KEY, active); 提供了一个状态。tab 不活跃时,跳过 check 函数,不执行。
6.2 useScrollParent 获取元素最近的可滚动父元素
获取元素最近的可滚动父元素。
给定参数 el, root 节点,遍历父级节点查找 style 包含 scroll|auto|overlay 的元素,如果没找到,返回第二个 root 参数(没有第二个参数则是 window)。
6.3 useRect 获取元素的大小及其相对于视口的位置
vant-contrib.gitee.io/vant/#/zh-C…
获取元素的大小及其相对于视口的位置,等价于 Element.getBoundingClientRect。

6.4 isHidden 是否隐藏
接着我们来分析开头的插槽部分。
7. 插槽
插槽部分基本都是有插槽用插槽没有则用默认的。
插槽是函数,比如 slots.default()。
7.1 renderFinishedText 渲染加载完成文字
7.2 renderErrorText 渲染加载失败文字
7.3 renderLoading 渲染 loading
8. 总结
我们主要分析了 List 组件 实现原理。
原理:使用 addEventListener 监听父级元素的 sroll 事件,用 Element.getBoundingClientRect 获取元素的大小及其相对于视口的位置,(滚动父级元素和占位元素计算和组件属性 offset(默认300) 属性比较),检测是否触底,触底则加载更多。
同时分析了一些相关组合式 API
useExpose暴露接口供this.$refs.xxx使用useEventListener绑定事件useTabStatus当前tab是否激活的状态useScrollParent获取元素最近的可滚动父元素useRect获取元素的大小及其相对于视口的位置
组件留有四个插槽,分别是:
default列表内容loading自定义底部加载中提示finished自定义加载完成后的提示文案error自定义加载失败后的提示文案
至此,我们就分析完了 List 组件,主要与 DOM 操作会比较多。List 组件 主文件的代码仅有 100 多行,但封装了很多组合式 API 。看完这篇源码文章,再去看 List 组件文档,可能就会有豁然开朗的感觉。再看其他组件,可能就可以猜测出大概实现的代码了。
如果是使用 react、Taro 技术栈,感兴趣也可以看看 taroify List 组件的实现 文档,源码。
如果看完有收获,欢迎点赞、评论、分享支持。你的支持和肯定,是我写作的动力。
9. 加源码共读群交流
最后可以持续关注我 @若川。我会写一个 组件库源码系列专栏,欢迎大家关注。
我倾力持续组织了一年 每周大家一起学习200行左右的源码共读活动,感兴趣的可以 点此扫码加我微信 ruochuan12 参与。
另外,想学源码,极力推荐关注我写的专栏 《学习源码整体架构系列》,目前是掘金关注人数(4.1k+ 人)第一的专栏,写有 20 余篇源码文章。
Last updated