源码目录设计
Vue.js 的源码都在 src 目录下,其目录结构如下。
src├── compiler # 编译相关 ├── core # 核心代码 ├── platforms # 不同平台的支持├── server # 服务端渲染├── sfc #.vue 文件解析├── shared # 共享代码
compiler
compiler 目录包含 Vue.js 所有编译相关的代码。它包括把模板解析成 AST 语法树,AST语法树优化,代码生成等功能。
编译的工作可以在构建时做(可以借助 webpack、vue-loader 等插件);也可以在运行时做,使用包含构建功能的 Vue.js。编译是一项耗性能的工作,所以更推荐前者——离线编译。
core
core 目录包含了 Vue.js 的核心代码,包括有内置组件、全局 API 封装,Vue 实例化、Obsever、Virtual DOM、工具函数 Util 等等。
platform
Vue.js 是一个跨平台的 MVVM 框架,它可以跑在 web 上,也可以配合 weex 跑在 native 客户端上。platform 是 Vue.js 的入口,2 个目录代表 2 个主要入口,分别打包成运行在 web 上和 weex 上的 Vue.js。
server
Vue.js 2.0 支持了服务端渲染,所有服务端渲染相关的逻辑都在这个目录下。注意:这部分代码是跑在服务端的 Node.js,不要和跑在浏览器端的 Vue.js 混为一谈。
服务端渲染主要的工作是把组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序。
sfc
通常我们开发 Vue.js 都会借助 webpack 构建, 然后通过 .vue 单文件来编写组件。
这个目录下的代码逻辑会把 .vue 文件内容解析成一个 JavaScript 的对象。
shared
Vue.js 会定义一些工具方法,这里定义的工具方法都是会被浏览器端的 Vue.js 和服务端的 Vue.js 所共享的。
接下来我们来找一下Vue的入口文件,我们接下来的分析都是基于platform为web的环境下进行的分析,从 package.json 和 config的 的打包配置中里可以看出,运行在web环境(Runtime only (CommonJS))的入口文件在web/entry-runtime.js下。
Vue入口文件
Vue入口文件目录 vue/src/core/instance/index.js
// vue/src/core/instance/index.jsimport{initMixin}from'./init'import{stateMixin}from'./state'import{renderMixin}from'./render'import{eventsMixin}from'./events'import{lifecycleMixin}from'./lifecycle'import{warn}from'../util/index'functionVue(options){if(process.env.NODE_ENV!=='production'&&!(thisinstanceofVue)){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)exportdefaultVue
采用的是ES5的写法,并不是ES6的Class写法的优点,是因为:
1、使用混入Mixin的方式传入Vue,为Vue的原型prototype上增加方法。class难以实现这种方法
2、此种方式将代码模块合理划分,将扩展分散到多个模块中去实现,使得代码文件不会过于庞大,便于维护和管理。这个编程技巧以后可以用于代码开发实现中。
通过Mixin增加的原型方法:
// vue/src/core/instance/index.jsinitMixin(Vue) // _initstateMixin(Vue) // $set、$delete、$watcheventsMixin(Vue) // $on、$once、$off、$emitlifecycleMixin(Vue) // _update、$forceUpdate、$destroy、renderMixin(Vue) // $nextTick、_render
initGlobalAPI
在 vue/src/core/index.js 中,调用的initGlobalAPI(Vue),是为Vue增加静态方法的,
在路径 vue/src/core/global-api/ 目录下的文件中,都是给Vue添加的静态方法
比如:
Vue.use// 使用pluginVue.extendVue.mixin Vue.component Vue.directive Vue.filter
有了这些基础的了解和一步步的跟踪查找后,我们一步一步找到了new Vue所在的位置,接下来我们来看下new Vue到底做了什么?
new Vue 做了什么
从入口的文件看来,通过new关键字初始化,调用了
// src/core/instance/index.jsthis._init(options)
然后从Mixin增加的原型方法看,initMixin(Vue),调用的是为Vue增加的原型方法_init
// src/core/instance/init.jsVue.prototype._init=function(options?:Object){constvm:Component=this........// expose real selfvm._self=vminitLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm,'beforeCreate')initInjections(vm)// resolve injections before data/propsinitState(vm)initProvide(vm)// resolve provide after data/propscallHook(vm,'created')........if(vm.$options.el){vm.$mount(vm.$options.el)}}
所以,从上面的函数看来,new vue所做的事情,就像一个流程图一样展开了,分别是
合并配置
初始化生命周期
初始化事件中心
初始化渲染
调用beforeCreate钩子函数
init injections and reactivity(这个阶段属性都已注入绑定,而且被$watch变成reactivity,但是$el还是没有生成,也就是DOM没有生成)
初始化state状态(初始化了data、props、computed、watcher)
调用created钩子函数。
在初始化的最后,检测到如果有 el 属性,则调用 vm.$mount 方法挂载 vm,挂载的目标就是把模板渲染成最终的 DOM。
Vue代码初始化的主线逻辑非常分明,使得逻辑和流程非常清楚,这种编程方法值得学习。
最后
现在的部分只是粗略的函数上讲了new Vue的过程和含义,接下来的文档会继续对Vue的源码进行学习和分析,会接着更细地分析在生命周期lifecyle下每一个函数后面具体所做的事情。
作者:Tiffany_c4df
链接:https://www.jianshu.com/p/3f4cec40be12
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。