Vue源码分析-Vue.use和vue-router

本文详细解析了Vue.js中Vue.use方法的工作原理,以及如何通过此方法注册插件。以vue-router为例,深入探讨了其安装过程,包括混入beforeCreate钩子、定义$router和$route属性,以及注册router-link和router-view组件。

Vue.use是Vue注册plugin的一种方法,那么这个过程中发生了什么?通过源码来看一下,vue注册plugin的过程。

这里我们以vue-router为例,顺便看一下vue-router的实现原理。

Vue.use源码分析

关于如何寻找源码,通过查找响应npm包的package.json文件中的main属性,这就是我们引入npm包的入口文件的路径。

function initUse (Vue) {
  Vue.use = function (plugin) {
    var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    var 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
  };
}
复制代码

查看这部分源码,我们可以发现vue首先判断这个插件是否被注册过,不允许重复注册。 并且接收的plugin参数的限制是Function | Object两种类型。 对于这两种类型有不同的处理。

如果我们传入的plugin(Vue.use的第一个参数)的install是一个方法。也就是说如果我们传入一个对象,对象中包含install方法,那么我们就调用这个plugin的install方法并将整理好的数组当成参数传入install方法中。 => plugin.install.apply(plugin, args) 如果我们传入的plugin就是一个函数,那么我们就直接调用这个函数并将整理好的数组当成参数传入。 => plugin.apply(null, args) 之后给这个插件添加至已经添加过的插件数组中,标示已经注册过 => installedPlugins.push(plugin) 最后返回Vue对象。

看看vue-router的注册过程

首先我们按照上面说的方法找到vue-router的源码

import View from './components/view'
import Link from './components/link'

export let _Vue

// 这里就是在Vue.use中会别执行的install方法
export function install (Vue) {
 if (install.installed && _Vue === Vue) return
 install.installed = true

 _Vue = Vue

 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实例混入beforeCreate钩子操作(后续可以继续看一下mixin的源码)
 Vue.mixin({
   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 () {
     registerInstance(this)
   }
 })
 // 通过Vue.prototype定义$router$route 属性(方便所有组件可以获取这两个属性)
 Object.defineProperty(Vue.prototype, '$router', {
   get () { return this._routerRoot._router }
 })

 Object.defineProperty(Vue.prototype, '$route', {
   get () { return this._routerRoot._route }
 })
 // Vue上注册router-link和router-view两个组件
 Vue.component('RouterView', View)
 Vue.component('RouterLink', Link)

 const strats = Vue.config.optionMergeStrategies
 // use the same hook merging strategy for route hooks
 strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}

复制代码

Install解析 (对应目录结构的install.js)

该方法内主要做了以下三件事:

  1. 对Vue实例混入beforeCreate钩子操作(在Vue的生命周期阶段会被调用)
  2. 通过Vue.prototype定义router、router、route 属性(方便所有组件可以获取这两个属性)
  3. Vue上注册router-link和router-view两个组件

转载于:https://juejin.im/post/5caf0739f265da03ae74b0ca

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值