vant4 源码

文章描述

本文为稀土掘金技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!

1. 前言

大家好,我是 若川arrow-up-right。我倾力持续组织了一年 每周大家一起学习200行左右的源码共读活动arrow-up-right,感兴趣的可以 点此扫码加我微信 ruochuan12 参与arrow-up-right。另外,想学源码,极力推荐关注我写的专栏 《学习源码整体架构系列》arrow-up-right,目前是掘金关注人数(4.1k+ 人)第一的专栏,写有 20 余篇源码文章。

我们开发业务时经常会使用到组件库,一般来说,很多时候我们不需要关心内部实现。但是如果希望学习和深究里面的原理,这时我们可以分析自己使用的组件库实现。有哪些优雅实现、最佳实践、前沿技术等都可以值得我们借鉴。

相比于原生 JS 等源码。我们或许更应该学习,正在使用的组件库的源码,因为有助于帮助我们写业务和写自己的组件。

如果是 Vue 技术栈,开发移动端的项目,大多会选用 vant 组件库,目前(2022-11-13) star 多达 20.4k。我们可以挑选 vant 组件库学习,我会写一个 组件库源码系列专栏arrow-up-right,欢迎大家关注。

学完本文,你将学到:

1. 学会如何用 vue3 + ts 开发一个 List 组件
2. 学会封装各种组合式 `API`
3. 等等

2. 准备工作

看一个开源项目,第一步应该是先看 README.mdarrow-up-right 再看贡献文档 github/CONTRIBUTING.mdarrow-up-right

2.1 克隆源码 && 跑起来

You will need Node.js >= 14arrow-up-right and pnpmarrow-up-right.

我们先来看 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 组件arrow-up-right 的实现,所以我们就不深入 vant-cli dev 命令了。

3. List 组件

List 组件文档arrow-up-right

瀑布流滚动加载,用于展示长列表,当列表即将滚动到底部时,会触发事件并加载更多列表项。

从这个描述和我们自己体验 demo 来。 至少有以下三个问题值得去了解学习。

  • 如何监听滚动

  • 如何计算滚动到了底部

  • 如何触发事件加载更多

带着问题我们直接找到 list demo 文件:vant/packages/vant/src/list/demo/index.vue。为什么是这个文件,我在上篇文章 跟着 vant4 源码学习如何用 vue3+ts 开发一个 loading 组件,仅88行代码arrow-up-right 分析了其原理,感兴趣的小伙伴点击查看。这里就不赘述了。

3.1 利用 demo 调试

组件源码中的 TS 代码我不会过多解释。没学过 TS 的小伙伴,推荐学这个 TypeScript 入门教程arrow-up-right。 另外,vant 使用了 @vue/babel-plugin-jsxarrow-up-right 插件来支持 JSX、TSX

4. 入口文件

主要就是导出一下类型和变量等。

withInstall 函数在上篇文章 5.1 withInstall 给组件对象添加 install 方法arrow-up-right 也有分析,这里就不赘述了。

我们可以在这些文件,任意位置加上 debugger 调试源码。

5. 主文件

List 组件 apiarrow-up-right

debugger 调试截图。

debugger 调试截图

接着我们来看其他一些事件。

5.1 一些事件 useExpose、useEventListener

由上面代码可以看出,check 函数非常重要,我们在下文分析它。

我们先分析上面代码用到的 useExposeuseEventListener 组合式 API

5.2 useExpose 暴露

通过 ref 可以获取到 List 实例并调用实例方法,详见 组件实例方法arrow-up-right

Vant 中的许多组件提供了实例方法,调用实例方法时,我们需要通过 ref 来注册组件引用信息,引用信息将会注册在父组件的 $refs 对象上。注册完成后,我们可以通过 this.$refs.xxx 访问到对应的组件实例,并调用上面的实例方法。

5.3 useEventListener 绑定事件

方便地进行事件绑定,在组件 mountedactivated 时绑定事件,unmounteddeactivated 时解绑事件。

useEventListener

6. steup check 函数

check 函数可以看出,主要就是利用滚动高度,接下来我们看这个函数中,使用到的组合式 APIuseTabStatususeScrollParentuseRect

6.1 useTabStatus tab 组件的状态

代码根据 commit 可以发现 useTabStatus 有这样一次提交。

fix(List): skip check when inside an inactive tabarrow-up-right

主要是在 van-tabs 组件中,provide(TAB_STATUS_KEY, active); 提供了一个状态。tab 不活跃时,跳过 check 函数,不执行。

6.2 useScrollParent 获取元素最近的可滚动父元素

获取元素最近的可滚动父元素。

给定参数 el, root 节点,遍历父级节点查找 style 包含 scroll|auto|overlay 的元素,如果没找到,返回第二个 root 参数(没有第二个参数则是 window)。

useScrollParent 文档arrow-up-right

6.3 useRect 获取元素的大小及其相对于视口的位置

vant-contrib.gitee.io/vant/#/zh-C…arrow-up-right

获取元素的大小及其相对于视口的位置,等价于 Element.getBoundingClientRectarrow-up-right

getBoundingClientRect

6.4 isHidden 是否隐藏

接着我们来分析开头的插槽部分。

7. 插槽

插槽部分基本都是有插槽用插槽没有则用默认的。

插槽是函数,比如 slots.default()

7.1 renderFinishedText 渲染加载完成文字

7.2 renderErrorText 渲染加载失败文字

7.3 renderLoading 渲染 loading

8. 总结

我们主要分析了 List 组件arrow-up-right 实现原理。

原理:使用 addEventListener 监听父级元素的 sroll 事件,用 Element.getBoundingClientRectarrow-up-right 获取元素的大小及其相对于视口的位置,(滚动父级元素和占位元素计算和组件属性 offset(默认300) 属性比较),检测是否触底,触底则加载更多。

同时分析了一些相关组合式 API

  • useExpose 暴露接口供 this.$refs.xxx 使用

  • useEventListener 绑定事件

  • useTabStatus 当前 tab 是否激活的状态

  • useScrollParent 获取元素最近的可滚动父元素

  • useRect 获取元素的大小及其相对于视口的位置

组件留有四个插槽,分别是:

  • default 列表内容

  • loading 自定义底部加载中提示

  • finished 自定义加载完成后的提示文案

  • error 自定义加载失败后的提示文案

至此,我们就分析完了 List 组件,主要与 DOM 操作会比较多。List 组件 主文件的代码仅有 100 多行,但封装了很多组合式 API 。看完这篇源码文章,再去看 List 组件文档arrow-up-right,可能就会有豁然开朗的感觉。再看其他组件,可能就可以猜测出大概实现的代码了。

如果是使用 reactTaro 技术栈,感兴趣也可以看看 taroify List 组件的实现 文档arrow-up-right源码arrow-up-right

如果看完有收获,欢迎点赞、评论、分享支持。你的支持和肯定,是我写作的动力

9. 加源码共读群交流

最后可以持续关注我 @若川arrow-up-right。我会写一个 组件库源码系列专栏arrow-up-right,欢迎大家关注。

我倾力持续组织了一年 每周大家一起学习200行左右的源码共读活动arrow-up-right,感兴趣的可以 点此扫码加我微信 ruochuan12 参与arrow-up-right

另外,想学源码,极力推荐关注我写的专栏 《学习源码整体架构系列》arrow-up-right,目前是掘金关注人数(4.1k+ 人)第一的专栏,写有 20 余篇源码文章。

Last updated