Vue源码解析(1)

纸上得来终觉浅,绝知此事要躬行,网上源码解析一大把,看着似懂非懂。
再来,用Vue也有一段时间了,遇到了很多问题以及疑虑,
(1)对一些官网的约定与建议依然心存疑虑;
(2)很想知道为什么Vue能跨平台支持weex;
(3)uni-app中遇到的相关问题;
这些都需要自己在源码中找答案。

1.目录结构

首先看Vue源码的目录结构,找到一条主线,先把大体流程结构摸清楚,再深入到细节,逐项击破。


Vue源码解析(1)_第1张图片
vue目录.png
Vue源码解析(1)_第2张图片
源码目录.png

2.new Vue核心代码分析

首先我们需要在源码中找到入口文件,首先看package.json,找到下面这句:

  "scripts": {
    "dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
      ...,
  }

发现Vue源码是众多module用的是rollup打包工具合并而成,本人只用过webpack...rollup不做分析。这里我们从package.json 中找到scripts/config.js的web-full-dev,找到entry-runtime-with-compiler.js文件。

 'web-full-dev': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.js'),
    format: 'umd',
    env: 'development',
    alias: { he: './entity-decoder' },
    banner
  },

然后在entry-runtime-with-compiler.js文件的多个引用中,一眼找到了 Vue 对象,确定入口来自core/index.js。

import Vue from 'core/index'

从这个引用得道vue的核心代码在core/index下面,那就先从src/core/index.js开始分析:

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'

initGlobalAPI(Vue) //初始化全局API

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
  value: FunctionalRenderContext
})

Vue.version = '__VERSION__'

export default Vue

这里不难看出index做了几件事:
(1)引入了对象,包括Vue构造方法,也就是'./instance/index'Vue的核心部分
(2)初始化全局API : initGlobalAPI(Vue)
(3)三个属性拦截器,其中前两个拦截监听Vue.prototype,另一个拦截监听Vue
(4)定义vue的版本
(5)导出Vue构造方法
也就是说,从 instance/index 中导入已经在原型上挂载了方法和属性后的 Vue,然后导入 initGlobalAPI 和 isServerRendering,之后将Vue作为参数传给 initGlobalAPI ,最后又在 Vue.prototype 上挂载了 、$isServer ,在 Vue 上挂载了 version 属性。
从引用来看,'./instance/index'是Vue的核心代码部分,所以值得进一步跟进去找/instance/index.js。

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

这个index做了哪些事:
(1)引入了一些需要Vue这个构造方法的方法
(2)Vue构造方法中调用初始化方法 this._init(options)
(3)将Vue转为参数,向引入的函数中传递
(4)将Vue默认导出
到这里,可以确从拿到源码到找到入口的步骤如下:
entry-runtime-with-compiler.js
-> runtime/index.js
-> core/index.js
->i nstance/index.js,

3. new Vue实例化过程

最熟悉的new Vue,也是Vue的初始化,当new Vue后到底发生了什么?

new Vue({
  el: ...,
  data: ...,
  ....
})

分析完源码后能分析得出:
(1)if 判断是否用new关键字实例化Vue,否则报错 warn('Vue is a constructor and should be called with the `new` keyword')
(2)初始化方法this._init(options) ,将options对象(data,props,methods,filters … )当参数传递
(3)调用方法:

initMixin(Vue) // _init
stateMixin(Vue) // $set、$delete、$watch
eventsMixin(Vue) // $on、$once、$off、$emit
lifecycleMixin(Vue) // _update、$forceUpdate、$destroy
renderMixin(Vue) // $nextTick、_render、以及多个内部调用的方法

写到这里,这一篇介绍到此,下一篇我们从this._init(options)开始。

你可能感兴趣的:(Vue源码解析(1))