vue-router的顶级路由为什么创建了5个vue实例?(最大的_uid=4)

888 阅读1分钟

问题描述

最近在看vue-router源码的时候,发现了一个问题:项目里的第一个路由,启动的时候竟然已经创建了5个vue实例了。跟随着好奇心,对代码进行研究后发现结果:

vuex创建了两个vue实例,剩下的三个请往下看。

项目是使用@vue/cli 4.4.6创建的,引入了vue-routervuex两个插件。

路由的定义如下图,只在routes数组的顶层创建了login组件,未使用children来嵌套子组件。

const routes = [{
    path: "/",
    redirect:"login"
  },
  {
    path: "/login",
    name: "login",
    component: login,
  }]

问题是如何出现的

接着就是问题的起源,请看console

图片1.png

哟?啥情况,就进了第一个页面login,程序就创建了5个vue实例。明明这一个页面只需要一个vue实例。这五个是什么意思?

这5条console是在项目的node_modules文件夹中vue-router中打出来的。vue-router中添加了一个beforeCreate的混入,我是在学习到这块时发现的这个问题。在此mixinconsole.log(this)便可得到此五条内容。

尝试解决问题--5个实例分别是怎么产生的

_uid=3,4

其实看console就可以看出来最后两个(_uid=3,4)的实例产生的原因。 注意看一下两张图片的el

图片3.png

图片2.png

_uid=4的vue实例挂载在class="appmain"的div上

_uid=3则对应的是id="app"的div

<template>
  <div id="app">
    <router-view class="appmain" />
  </div>
</template>
<script>

上面的代码在App.vue文件中
由此可以看出来第4个vue实例是父组件<div id="app">产生的,
第5个vue实例是子组件<router-view class="appmain" />产生的。

_uid=2

那么第三个在哪呢?答案是在main.js文件。

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

此前我一直认为此处的new Vue({...}).$mount("#app")产生的vue实例,和App.vue文件中_uid=3的那个vue实例应该是同一个。因为这两个都挂载在了#app上面。

官方文档中对$mount()的解释:

如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个未挂载的实例。

从语义中分析,vm.$mount()是vm实例去挂载另一个实例。所以猜测_uid=2的实例是main.js文件中创建的。

接下来对我的想法进行验证:
App.vue

<template>
  <div id="app">
    <router-view class="appmain" />
  </div>
</template>
<script>
export default {
  beforeCreate() {
    console.log("-------------------");
    console.log("App.vue");
    console.log(this);
  },
};
</script>

main.js

new Vue({
  router,
  store,
  render: (h) => h(App),
  beforeCreate(){
    console.log("-------------------");
    console.log('main.js')
    console.log(this);
  }
}).$mount("#app");
</script>

OK,下面是结果:

图片4.png

可以看到_uid=2对应的就是main.js上创建的实例。

_uid=0,1

这两个是vuex里创建的。忽然不想写了,就这样吧,想看自己去看。