vue.use的作用及原理

前言

在vue中引入第三方库通常我们都会采用import的形式引入进来,但是有的组件在引入之后又做了Vue.use()操作,有的组件引入进来又进行了vue.prototype.$axios = axios类似的操作,那么它们之间有什么联系呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 最常见的方式,use后可以全局使用
import ElementUI from 'element-ui';

Vue.use(ElementUI);

// 不需要use,但是每次引用需要再次import
import axios from 'axios';

axios
.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone',
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

// 使用vue.component,也可以全局使用
import Pagination from '@/components/Pagination';

Vue.component('Pagination', Pagination);

// 挂载到vue的原型,全局使用this.$download使用
import { download } from '@/utils/index';

Vue.prototype.$download = download;

Vue.use是什么

emmmm,似乎不太好理解?我们来看看源码,Vue.use()后做了哪些事儿。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Vue.use = function (plugin) {
// 已安装的插件列表
const installedPlugins =
this._installedPlugins || (this._installedPlugins = []);
// 阻止多次注册相同的插件
if (installedPlugins.indexOf(plugin) > -1) {
return this;
}
// 取出vue.use() 传入的参数并转为数组
const args = toArray(arguments, 1);
// 将vue对象填充到第一位, 最后的结构为[vue,arg1,arg2,...]
args.unshift(this);
// 判断插件是否有install方法,如果有执行install方法,如果没有直接把插件当install执行
if (isFunction(plugin.install)) {
plugin.install.apply(plugin, args);
} else if (isFunction(plugin)) {
plugin.apply(null, args);
}
installedPlugins.push(plugin);
return this;
};

看起来精髓在插件的install方法,那我们来看看执行插件的install后发生了什么?

install 后发生了什么

vue-router为例,来看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
install (app) {
const router = this;
// 将RouterLink、RouterView注册为全局组件
app.component("RouterLink", RouterLink);
app.component("RouterView", RouterView);
// 将$router注册为全局对象,可以使用this.$router访问
app.config.globalProperties.$router = router;
Object.defineProperty(app.config.globalProperties, "$route", {
enumerable: true,
get: () => unref(currentRoute),
});
const reactiveRoute = {};
for (const key in START_LOCATION_NORMALIZED) {
reactiveRoute[key] = computed(() => currentRoute.value[key]);
}
// 通过 provide 方式全局注入 router 对象和 reactiveRoute 对象,通过 router 可以动态操作路由,reactiveRoute 是响应式路径对象,维护了当前的路径信息
app.provide(routerKey, router);
app.provide(routeLocationKey, reactive(reactiveRoute));
app.provide(routerViewLocationKey, currentRoute);
const unmountApp = app.unmount;
installedApps.add(app);
// 重写 Vue 的 unmount 方法,在应用卸载的时候先清理路由,然后再调用原始的 unmount 方法
app.unmount = function () {
installedApps.delete(app);
if (installedApps.size < 1) {
pendingLocation = START_LOCATION_NORMALIZED;
removeHistoryListener && removeHistoryListener();
removeHistoryListener = null;
currentRoute.value = START_LOCATION_NORMALIZED;
started = false;
ready = false;
}
unmountApp();
};
};

FAQ

为什么axios不需要vue.use(axios),可以开箱即用?

理由也很简单,跟上面需要install的相反。因为axios是基于Promise封装的库,是完全独立于Vue的,根本不需要挂载在Vue上也能实现发送请求。

为什么说“当 install 方法被同一个插件多次调用,插件将只会被安装一次”

use源码中,我们可以发现使用了全局的数组_installedPlugins来存储已经安装过的插件,已经安装过直接返回当前实例。

Vue.use()和Vue.prototype的区别

Vue.prototype.$xx原理是利用了js中函数原型的特性。 函数原型上的属性/方法, 在函数实例化后, 可以在任意实例上读取。而vue.use是调用插件的install方法在vue的实例中注册组件/方法。

参考资料:
vue官方文档
vue3源码分析之use(store)
JS每日一题: Vue.use中都发生了什么?
Vue Router 源码学习
【面试题】为什么有时用Vue.use()?及Vue.use()的作用及原理是什么?


vue.use的作用及原理
https://xypecho.github.io/2023/02/15/vue-use的作用及原理/
作者
很青的青蛙
发布于
2023年2月15日
许可协议