前言:在使用ui框架时,总是少不了对ui框架的好奇心,一个优秀的ui框架总能让人用的得心应手,在这 respect 框架的开发者们
1.找到源码的位置
import {Tabs,Tab} from 'vant'
import 'vant/lib/index.less'
这是我们最熟悉的按需引入代码步骤了,那么在引入的过程中,会自动解析到node_modules中的 _vant@2.12.4@vant
的es文件夹中,那么重点关注 tabs和tab这两个文件夹
2.梳理tabs结构
在tabs的index.js中,可以看到如下代码:
这里体现了两个重要的函数 createComponent
和 bem
1.createComponent
作用:为 vant 创建特定语法的组件
function install(Vue) {
var name = this.name; Vue.component(name, this);
Vue.component(camelize("-" + name), this);
}
export function createComponent(name) {
return function (sfc) {
if (isFunction(sfc)) {
sfc = transformFunctionComponent(sfc); // 转化成函数式组件
}
if (!sfc.functional) {
sfc.mixins = sfc.mixins || [];
sfc.mixins.push(SlotsMixin);
}
sfc.name = name;
sfc.install = install; // 这里的install实际上就是vant实现按需导入的关键
return sfc;
};}
2.bem
作用:为 vant 生成特定的类名,注意绿色部分,注释已经写得很明白了,无需去关注太多的功能实现,只需要知道传进来生成的是什么就行
3. render 函数
在 tabs --> index.js中,我们可以很清晰地看到,官方并没有使用我们日常在单文件组件书写的
<template>
来书写页面Dom结构,而是采用了render函数进行渲染
对于render函数,官方是这么解释的:
"Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器"
可以发现,render函数的性能要比我们平日书写的<template>
性能要好,这也难怪vant会使用其编写Dom结构了。
在了解Vue render函数之前,我强烈推荐你阅读这篇文档:渲染器 ,这能够使你对Vue渲染器的设计,以及实现有着更深刻的了解。(感谢大神的辛勤付出)
接下来直接移步官方文档之 createElement参数 , 对需要传入的参数、格式有所了解后,来看看tabs中render的代码:
【题外话:第一眼看到的时候,我直接靓仔语塞,这也太多太复杂了。。。但是,我从来就不是一个轻易就放弃的人,那就继续研究下去!当然我不建议直接看,我的思路是从实际渲染的DOM入手,一点一点去理解它生成的过程。】
3. tabs DOM结构
<van-tabs v-model="active">
<van-tab title="标签 1">内容 1</van-tab>
<van-tab title="标签 2">内容 2</van-tab>
<van-tab title="标签 3">内容 3</van-tab>
<van-tab title="标签 4">内容 4</van-tab>
</van-tabs>
生成的DOM结构如下:
从 tabs渲染出来的Dom结构我们可以看到,大体分为两大DOM部分,分别为
wrap
和content
,它们分别对应了导航区(也就是在tab中绑定的title)和内容区,然后最后会由一个大的div进行包裹。
1.wrap的生成过程
在wrap中,我们可以看到最外层的DOM为
van-tabs__nav
,那么我们从render中,看看这个Dom是如何生成的。
如果你已经学习过之前的文档,那么你应该知道h函数
是用来生成一个VNode节点的,相当于createElement函数
,如图,我们可以知道Nav是通过遍历children(这里指van-tab) ,然后将children中所绑定的属性赋值给Title。那么问题来了,Title是什么类型?
通过引入的title.js进行追踪,不难发现:
oh,原来Title是个组件!首先看看render,可以发现this.genText()
就是我们在vant-tab上绑定的title值,经过一番处理,最终会生成 <div><span>标签1</span></div>
的DOM结构!
那么最后,这个Nav所代表的,就是我们想要的导航栏,也就是我们在vant-tab上所绑定的title值。如图,我们可以看到,它最终会被一个wrap所包裹住。
2. content的生成过程
其实看懂wrap的生成过程,content也是同理,我们通过引入的content.js,不难看到
content也是个组件,但是它最终渲染出来的DOM只是<div class='van-tabs__content'></div>
不免思考,那所写的内容哪去了呢?别忘了,这个标题叫做 【tabs 的DOM结构】,剩下的内容渲染,就在tab --> index.js 中进行~
4.mixins
在源码中,发现vant大量使用mixins,在以前的单文件组件开发中,我却很少用到,不免又勾起了我的好奇心,于是乎,先阅读了一下官方文档 --> vue混入
在content.js中,可以看到vant使用了TouchMixin
找到TouchMixin,如下:
可以看到vant在这个mixin中,定义了我们常见的滑动函数,这就大幅度地提高了复用性。不禁引发一阵思考:以前我在封装函数的时候,会考虑用大量的js文件进行封装,一旦多了起来,会变难以维护。在单个页面需要对多个函数进行调用时,其实可以将这些通用的函数,放入到mixin中,有了mixin后,其实更方便了~
5.总结
其实tab谁都会做,但要做到像ui框架这种复用性极强,定义的API又很人性化,还需要仔细打磨,考虑多种情况才行。前人栽树,我在乘凉时,也想看看前人是如何 “栽树” 的~