首先来思考几个问题:
Vue.use是什么?
vue.use() 是vue提供的一个静态方法,主要是为了注册插件,增加vue的功能。
Vue.use( plugin )
plugin只能是Object 或 Function
vue.use()做了什么工作?
- 该js如果是对象
- 该对象里面要有一个install方法
- Vue.use就是调用里面的install方法
- 该js是一个function
- Vue.use时function会直接执行
- 作用
- 可以在Vue的原型加一些东西
- 注册全局组件等
- 使用
- 将hellow注册为全局组件
- 在原型中添加$num= 123
1、在components中新建components.js
import HelloWorld from '@/components/HelloWorld.vue'
export default {
install: function (Vue) {
// 这里的Vue就是你调用install方法时传递过来的
// 可以在Vue原型中加一些东西
Vue.prototype.$num = 123
// 注册全局组件
Vue.component(HelloWorld.name, HelloWorld)
}
}
2、在main.js中调用
import App from './App.vue'
import components from '@/assets/components.js'
Vue.use(components)
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount('#app')
3、Helloworld.vue
<template> <div> <h1>这里是HelloWord</h1> <h2>{{ $num }}</h2> </div> </template> <script> export default { name: 'HelloWorld' } </script> <style></style>
- 该js为对象时,component.js写法不一样,其他均一样
Vue.use(VueRouter)就是这么实现的
export default function (Vue) { Vue.component(HelloWorld.name, HelloWorld) Vue.prototype.$num = 123 } function install (Vue) { if (install.installed && _Vue === Vue) { return } install.installed = true; _Vue = Vue; var isDef = function (v) { return v !== undefined; }; var registerInstance = function (vm, callVal) { var i = vm.$options._parentVnode; if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) { i(vm, callVal); } }; Vue.mixin({ beforeCreate: function beforeCreate () { if (isDef(this.$options.router)) { this._routerRoot = this; this._router = this.$options.router; this._router.init(this); Vue.util.defineReactive(this, '_route', this._router.history.current); } else { this._routerRoot = (this.$parent && this.$parent._routerRoot) || this; } registerInstance(this, this); }, destroyed: function destroyed () { registerInstance(this); } }); Object.defineProperty(Vue.prototype, '$router', { get: function get () { return this._routerRoot._router } }); Object.defineProperty(Vue.prototype, '$route', { get: function get () { return this._routerRoot._route } }); Vue.component('RouterView', View); Vue.component('RouterLink', Link); var strats = Vue.config.optionMergeStrategies; // use the same hook merging strategy for route hooks strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created; }
Object.defineProperty(Vue.prototype, '$router', { get: function get () { return this._routerRoot._router } }); Object.defineProperty(Vue.prototype, '$route', { get: function get () { return this._routerRoot._route } });
其核心就是以上两行代码在install方法中将$router和route挂载到Vue原型上
官方对 Vue.use() 方法的说明:通过全局方法 Vue.use() 使用插件,Vue.use 会自动阻止多次注册相同插件,它需要在你调用 new Vue() 启动应用之前完成,Vue.use() 方法至少传入一个参数,该参数类型必须是 Object 或 Function,如果是 Object 那么这个 Object 需要定义一个 install 方法,如果是 Function 那么这个函数就被当做 install 方法。在 Vue.use() 执行时 install 会默认执行,当 install 执行时第一个参数就是 Vue,其他参数是 Vue.use() 执行时传入的其他参数。就是说使用它之后调用的是该组件的install 方法。
在Vue中引入使用第三方库通常我们都会采用import的形式引入进来,但是有的组件在引入之后又做了Vue.use()操作,有的组件引入进来又进行了Vue.prototype.$something = something,那么它们之间有什么联系呢?
先说一下vue.prototype, 在vue项目中通常我们引入axios来进行请求接口数据,通过pnpm 安装axios之后我们只需要在文件中导入improt axios from ‘axios’就可以使用,有时候我们会加上一句vue.prototype.$axios=axios
Vue.prototype.axios=axios,其实是在vue的原型上增加了一个axios,通过在全局注册这个方法,然后在周后的文件中都可以通过$axios直接来使用axios
Vue.use() 的源码中的逻辑
export function initUse (Vue: GlobalAPI) { Vue.use = function (plugin: Function | Object) { const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) if (installedPlugins.indexOf(plugin) > -1) { return this } const args = toArray(arguments, 1) args.unshift(this) if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args) } else if (typeof plugin === 'function') { plugin.apply(null, args) } installedPlugins.push(plugin) return this } }
在源码中首先限制了它传入的值的类型只能是Function或者Object,然后判断了该插件是不是已经注册过,防止重复注册,然后调用了该插件的install方法,源码中也有介绍到Vue.use()可以接受多个参数的,除第一个参数之后的参数我们都是以参数的形式传入到当前组件中。