首先,从Vant组件的使用开始。
// js
import Vue from 'vue';
import {
Button } from 'vant'; // 导入 Button
Vue.use(Button); // 注册 Button
// template
<van-button type="primary">主要按钮</van-button>
源码第一部分
// src/button/index.tsx 01 这里主要导入一些函数和类型
// 函数:useRoute createNamespace
// 类型:PropType CSSProperties routeProps LoadingType (用来进行ts类型校验)
// 常量:BORDER_SURROUND
// 其他组件:Icon Loading
import {
PropType, CSSProperties } from 'vue';
// Utils
import {
createNamespace } from '../utils';
import {
BORDER_SURROUND } from '../utils/constant';
import {
useRoute, routeProps } from '../composables/use-route';
// Components
import Icon from '../icon';
import Loading, {
LoadingType } from '../loading';
const [createComponent, bem] = createNamespace('button');
这里,我们只看函数部分,通过 导入路径,我们找到了useRoute createNamespace 两个函数的实现。
useRoute
// src/composables/use-route.tsx
import {
PropType,
ExtractPropTypes,
getCurrentInstance,
ComponentPublicInstance,
} from 'vue';
import type {
RouteLocationRaw } from 'vue-router';
export const routeProps = {
to: [String, Object] as PropType<RouteLocationRaw>,
url: String,
replace: Boolean,
};
export type RouteProps = ExtractPropTypes<typeof routeProps>;
export function route(vm: ComponentPublicInstance<RouteProps>) {
...
}
export function useRoute() {
...
}
官方的注释是“Vue Router support”,我们抛开类型判断,来看它是如何实现的。这里,重要的是route和useRoute两个函数。
export function route(vm: ComponentPublicInstance<RouteProps>) {
// 入参为一个vue对象vm
const router = vm.$router;
// 获取 vm 的 router。
// router:vue-router提供的api,可以调用其上的replace、push进行路由切换.注册时被挂载在vm上,通过vm.$router可以获取。注意和route做区分。
const {
to, url, replace } = vm; // 拿到vm上的路由信息
if (to && router) {
router[replace ? 'replace' : 'push'](to); // 调用 router 的方法进行路由切换
} else if (url) {
replace ? location.replace(url) : (location.href = url);
// 如果只有 url,可能是因为router不存在。使用系统提供的 location 进行路由切换。
}
}
route 函数实际上就是对传入的 Vue实例 vm 进行了根据存储在 vm 上的路由信息一次路由切换。在切换时,会优先使用router,如果没有router,则会使用 location。
接下来是useRoute的代码:
export function useRoute() {
const vm = getCurrentInstance()!.proxy as ComponentPublicInstance<RouteProps>;
return () => {
route(vm);
};
}
很简单的步骤,获取当前 vue 实例,返回一个函数,函数里调用了一次route(vm)
。这里是一个闭包结构,将vm了保存起来,这样,如果需要对当前vue实例进行一次路由切换时,就不需要再去获取了。
createNamespace
import {
createBEM } from './bem';
import {
createComponent } from './component';
import {
createTranslate } from './translate';
export function createNamespace(name: string) {
name = 'van-' + name;
return [
createComponent(name),
createBEM(name),
createTranslate(name),
] as const;
}
这个函数,将传入的 name 加上了van-
的前缀,然后,使用 name 调用了 三个函数 createComponent
createBEM
createTranslate
,并将结果作为数组返回。
这里,我们看到这一阶段最后一个行代码
const [createComponent, bem] = createNamespace('button');
为了节省篇幅,我们就只看createComponent
createBEM
的代码。
createComponent
import {
App, defineComponent, ComponentOptionsWithObjectProps } from 'vue';
import {
camelize } from '../format/string';
export function createComponent(name: string) {
return function (sfc: ComponentOptionsWithObjectProps)