Vue源码之入口new Vue做了啥

1,222

数据驱动

Vue.js ⼀个核⼼思想是数据驱动。所谓数据驱动,是指视图是由数据驱动⽣成的,我们对视图的修改,不会直接操作 DOM,⽽是通过修改数据简言之就是js对象数据格式。DOM 变成了数据的映射,我们所有的逻辑都是对数据的修改,⽽不⽤碰触 DOM,便于维护的同时提升了性能。

目标

寻找入口以及模板数据渲染成DOM在页面中显示的流程。

new Vue入口在哪 发生了什么

1.下载vue源码

github搜索vue直接下载 或者 git命令:git clone -b dev https://github.com/vuejs/vue

  1. 目录结构

  1. 术语解释
  • runtime:仅包含运行时,不包含编译器
  • common:cjs规范,用于webpack1
  • esm:ES模块,用于webpack2+
  • umd:(什么都不带如vue.js)universal module defintion,兼容cjs和amd,用于浏览器
  1. 找入口
  • package.json
  • scripts/config.js找到web-full-dev
  • 此时web是啥不清楚 查看resolve 显然这里对名字做了别名的处理
  • 找到scripts/alias.js

所以全路径就是src/platforms/web/entry-runtime-with-compiler.js

  • src/platforms/web/entry-runtime-with-compiler.js入口文件,重写mount,定义模板有三种方式el,template,render,执行模板解析和编译工作。

上面代码⾸先缓存了原型上的 mount ⽅法,再重新定义该⽅法,我们先来分析这段代码。⾸先,它对 el 做了限制,Vue 不能挂载在 body 、 html 这样的根节点上。接下来如果没有定义 render ⽅法,则会把 el 或者 template 字符串转换成 render ⽅法。在 Vue 2.0 版本中,所有 Vue 的组件的渲染最终都需要 render ⽅法,⽆论我们是⽤单⽂件.vue ⽅式开发组件,还是写了 el 或者 template 属性,最终都会转换成 render ⽅法,那么这个过程是 Vue 的编译的过程,它是调⽤ compileToFunctions ⽅法实现的,编译过程我们后面再说。最后,调⽤原先原型上的 mount ⽅法挂载。

  • 寻找vue构造函数
  • src/platforms/web/runtime/index.js 定义mount
  • src/core/index 定义全局api
  • src/core/instance/index 定义构造函数,这里可以看到初始化执行_init()方法
  • 进入initMixin() src/core/instance/init 定义初始化方法

Vue 的挂载过程

  1. 在examples下创建文件夹test/01-init.html 浏览器打开
  1. 断点执行位置 执行到断点处进入
  1. 执行到断点处进入(src/core/instance/index.js)
  1. 执行到断点处进入(src/core/instance/init.js)
  1. 执行到断点处进入(src/platforms/web/entry-runtime-with-compiler.js)
  1. 执行到断点处进入(src/platforms/web/runtime/index.js)

上面代码mount ⽅法⽀持传⼊ 2 个参数,第⼀个是 el ,它表⽰挂载的元素,如果存在并且浏览器环境下会调⽤ query ⽅法转换成 DOM 对象。第⼆个参数是和服务端渲染相关,在浏览器环境下我们不需要传第⼆个参数。

  1. $mount ⽅法实际上会去调⽤ mountComponent (src/core/instance/lifecycle.js) 两个地方断点 第一次执行会先到4074行创建一个watcher 第二次执行会到4067行然后进入

上⾯代码中, 可以看到mountComponent 核⼼就是先调⽤ vm._render ⽅法先⽣成虚拟 Node,再实例化⼀个Watcher ,在它的回调函数中会调⽤ updateComponent ⽅法,最终调⽤vm._update 更新 DOM。

Watcher 在这⾥起到两个作⽤,⼀个是初始化的时候会执⾏回调函数,另⼀个是当 vm 实例中的监测的数据发⽣变化的时候执⾏回调函数。

最后判断是否为根节点设置 vm._isMounted 为 true , 表⽰这个实例已经挂载了,同时执⾏mounted 钩⼦函数。 这⾥vm.vnode 表⽰ Vue 实例的⽗虚拟 Node,所以它为 Null 则表⽰当前是根 Vue 的实例。

  1. 此时进入的是vm._render方法获取虚拟dom 执行到断点处进入会退出到上个界面然后再次进入(src/core/instance/render.js)
  1. 再次进入的是vm._update方法 把虚拟dom转换为真实dom然后替换el节点渲染到页面(src/core/instance/lifecycle.js)
  1. 执行完3946行跳到下一步页面结果显示

总结:

下篇我们深入看看vm._update和vm._render做了些啥。