Vue.use() 的作用及原理
本文原文讨论的是 Vue 2 的全局 API。Vue 2.7 仍可使用
Vue.use(),但 Vue 2 已于 2023 年 12 月 31 日结束维护。Vue 3 应使用createApp()创建应用,再通过app.use()安装插件。下面保留 Vue 2 的历史原理,并补充当前写法。
在 Vue 中引入第三方库通常使用 import。有些库引入后还要执行 Vue.use(),有些库则会写成 Vue.prototype.$something = something。它们都和“把能力接入组件实例或应用”有关,但不是同一件事。
Vue.prototype 做了什么?
以 axios 为例,直接导入后,普通 JavaScript 模块可以这样使用:
import axios from 'axios'
axios.get('/api/users')
在 Vue 2 项目中,也可以把它挂到 Vue 构造函数的原型上:
import Vue from 'vue'
import axios from 'axios'
Vue.prototype.$axios = axios
这样安装后,组件实例可以通过 this.$axios 使用它,模板也可以访问 $axios。它不会让任意 JavaScript 文件凭空获得 $axios;普通模块仍应直接 import axios,或者通过其他依赖注入方式取得实例。

上图是原文的历史截图,仅用于说明 Vue 2 原型注入;Vue 3 不再使用
Vue.prototype。
Vue.use() 是什么?
Vue 2 官方将 Vue.use() 定义为安装插件的全局方法:
- 插件对象应提供
install方法。 - 如果插件本身是函数,就把这个函数当作安装函数。
- Vue 2 调用安装函数时,第一个参数是
Vue构造函数,后面是Vue.use(plugin, options)传入的额外参数。 - 同一个插件对象在同一个 Vue 构造函数上重复安装时只会执行一次。
- 通常应在
new Vue()创建根实例之前安装插件。
例如:
import Vue from 'vue'
import Element from 'element-ui'
Vue.use(Element, { size: 'small' })
new Vue({
render: h => h(App)
}).$mount('#app')
“需要使用 Vue.use()”并不是说所有第三方库都必须使用它,而是说该库需要通过安装函数完成全局注册、注入或配置。axios 本身是独立的请求库,不依赖 Vue;直接 import 即可使用,也可以由项目自行封装成插件。
Vue 2 中 Vue.use() 的源码逻辑
下面是 Vue 2.7 src/core/global-api/use.ts 中的核心逻辑整理。这里的 Function | Object 是 API 的类型约定,不应理解为运行时会对所有非法值做完整的类型校验:
export function initUse(Vue) {
Vue.use = function (plugin) {
const installedPlugins =
this._installedPlugins || (this._installedPlugins = [])
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// Vue.use(plugin, option1, option2) 中除 plugin 外的参数
const args = toArray(arguments, 1)
args.unshift(this) // 第一个参数变为 Vue 构造函数
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
这段逻辑可以概括为:
- 取得当前 Vue 构造函数已经安装过的插件列表。
- 如果同一个插件对象已经安装,直接返回,不重复执行。
- 把 Vue 构造函数和额外选项传给插件的
install函数。 - 记录插件并返回 Vue 构造函数,使
Vue.use(...).use(...)这类链式调用成为可能。
插件的安装函数可以注册全局组件、指令、混入、实例属性或其他全局能力。例如:
const plugin = {
install(Vue, options = {}) {
Vue.prototype.$message = message => {
console.log(options.prefix, message)
}
}
}
Vue.use(plugin, { prefix: '[app]' })
Vue 3 的当前写法
Vue 3 将全局 API 从 Vue 构造函数迁移到应用实例。插件的安装函数接收 app,而不是 Vue 构造函数:
// plugins/api.js
export default {
install(app, options = {}) {
const api = createApi(options.baseURL)
// 让组件实例可以通过 this.$api 访问
app.config.globalProperties.$api = api
// 也可以让 Composition API 通过 inject() 访问
app.provide('api', api)
}
}
import { createApp } from 'vue'
import App from './App.vue'
import apiPlugin from './plugins/api'
const app = createApp(App)
app.use(apiPlugin, { baseURL: '/api' })
app.mount('#app')
Vue 3 中常见的插件能力包括:
app.component()注册全局组件。app.directive()注册全局指令。app.provide()提供可注入的资源。app.config.globalProperties添加少量全局实例属性或方法。
globalProperties 应节制使用;如果只是组件树内部共享状态,优先考虑 provide/inject、composable 或 Pinia。插件安装状态也按 app 实例隔离:同一个插件可以分别安装到两个 app 中,而不会像 Vue 2 那样修改同一个 Vue 构造函数的全局状态。
自己编写一个插件
Vue 2 历史写法:
// api-plugin.js
const apiList = {
login,
home,
detail
}
export default {
install(Vue) {
Object.defineProperty(Vue.prototype, '$api', {
get() {
return apiList
}
})
}
}
import Vue from 'vue'
import apiPlugin from './api-plugin'
Vue.use(apiPlugin)
new Vue({ render: h => h(App) }).$mount('#app')
Vue 3 对应的是应用级安装:
// api-plugin.js
export default {
install(app) {
app.config.globalProperties.$api = apiList
app.provide('api', apiList)
}
}
在 <script setup> 中通常使用注入的资源:
<script setup>
import { inject } from 'vue'
const api = inject('api')
</script>
总结
import只是加载模块;插件安装还可能需要注册组件、指令、注入依赖或配置应用。- Vue 2 的
Vue.use()调用plugin.install(Vue, ...options),并对同一 Vue 构造函数去重。 - Vue 2 的
Vue.prototype.$api只会成为组件实例属性,不是通用模块变量。 - Vue 3 使用
app.use(plugin, ...options)、app.config.globalProperties和app.provide()。 - axios 不需要安装并不代表它不能被封装成插件,只是它本身不依赖 Vue 的全局注册机制。
官方参考
- Vue 2:插件(历史)
- Vue 2 API:Vue.use(历史)
- Vue 2.7.16:Vue.use 源码
- Vue 3:插件
- Vue 3:app.use
- Vue 3:app.config.globalProperties
- Vue 3:全局 API 迁移
作者:国服第一摸鱼选手
原文链接:https://juejin.cn/post/7138216381283205128
来源:稀土掘金。著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。