1.使用Vuex,Vue.use(Vuex),搞明白Vue.use 都做了什么
Vue 源码src/core/global-api/use.js
/* @flow */
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
/* istanbul ignore if */
if (plugin.installed) {
return
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else {
plugin.apply(null, args)
}
plugin.installed = true
return this
}
}
从Vue.use这里可以看出入参plugin,首先判断plugin安装状态,安装直接返回,没有安装则继续下面的流程
const args = toArray(arguments, 1) 为Vue.use(Vuex, ...),...省略的参数,并转换成一个数组,args.unshift(this)将this放入到args的第一向,如果plugin.install 是一个方法就执行plugin.install.apply(plugin, args); 使用apply调用plugin.install 方法,并将该方法里面的this指向plugin,args为数组(apply用法大家可以自行百度)
plugin.install.apply(plugin, args):执行plugin.install 执行上下文为plugin,args为[Vue,...其他参数];
plugin.apply(null, args): plugin 执行上下文为null,args args为[Vue,...其他参数];
2.查看plugin.install 的实现,Vuex 是plugin.install 为一个方法,vue-router则直接是导出一个function
a.
vuex/src/index.js
function install (_Vue) {
if (Vue) {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
return
}
Vue = _Vue
applyMixin(Vue)
}
// auto install in dist mode
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
export default {
Store,
install,
version: '__VERSION__',
mapState,
mapMutations,
mapGetters,
mapActions
}
install 方法如上,install的参数为上方调用的args [Vue, ...其他参数], _Vue即Vue
b.调用applyMixin,如下
export default function (Vue) {
const version = Number(Vue.version.split('.')[0])
if (version >= 2) {
const usesInit = Vue.config._lifecycleHooks.indexOf('init') > -1
Vue.mixin(usesInit ? { init: vuexInit } : { beforeCreate: vuexInit })
} else {
// override init and inject vuex init procedure
// for 1.x backwards compatibility.
const _init = Vue.prototype._init
Vue.prototype._init = function (options = {}) {
options.init = options.init
? [vuexInit].concat(options.init)
: vuexInit
_init.call(this, options)
}
}
/**
* Vuex init hook, injected into each instances init hooks list.
*/
function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store = options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
}
调用default function,判断vue 版本,>2.0,Vue.mixin(usesInit ? { init: vuexInit } : { beforeCreate: vuexInit }),使用mixin混入init或者是beforeCreate 生命周期函数中,当生命周期函数调用时候就执行混入的方法
vuexInit, 查看组件上面的$options属性是否存在store 属性(根节点传入的store),否则查看该组件的父组件是否存在$store(一般来讲必须会存在的,可以形成每次都是查找父组件的$store,就会形成每个组件都具备$store 属性)
3.vue-router 直接导出一个function,会进入1.initUse 中的plugin.apply(null, args)该分支
vue-router/src/install.js
import View from './components/view'
import Link from './components/link'
export let _Vue
export function install (Vue) {
if (install.installed) return
install.installed = true
_Vue = Vue
Object.defineProperty(Vue.prototype, '$router', {
get () { return this.$root._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () { return this.$root._route }
})
const isDef = v => v !== undefined
const registerInstance = (vm, callVal) => {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
Vue.component('router-view', View)
Vue.component('router-link', Link)
const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.created
}
Object.defineProperty(Vue.prototype, '$router', {
get () { return this.$root._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () { return this.$root._route }
})
直接挂载在Vue.prototype原型上面,组件内部可以使用this.$router,this.$route
this.$router每次会调用Vue.prototype.$router 的get 放方法
this.$route每次会调用Vue.prototype.$router 的get 放方法