实例讲解vue源码架构


Posted in Javascript onJanuary 24, 2019

下载

去github上下载Vue https://github.com/vuejs/vue

npm install 
npm run dev

运行起来

rollup + flow

vue使用使用rollup打包,flow规范数据类型

rollup可以先用webpack套用,读起来差不多,时间有限,毕竟只有5分钟,这个就不用去看rollup文档了

入口

打开package.json

我们看scripts配置

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

找到scripts/config.js

打开

根据配置TARGET的不同会选择不同的config

同时在这里配置了process.env.NODE_ENV 环境

TARGET有CommonJS,ES Modules,UMD关于js引入类型的

还有weex,ssr

'web-runtime-cjs-dev': {
  entry: resolve('web/entry-runtime.js'),
  dest: resolve('dist/vue.runtime.common.dev.js'),
  format: 'cjs',
  env: 'development',
  banner
 }

在alias.js下设置了别名路径

我们先介绍src/platforms

里面有web和weex 分别的web和weex入口

在web文件下是CommonJS,ES Modules,UMD关于js引入类型,server的打包入口

打开web/entry-runtime.js

引入

import Vue from './runtime/index'
export default Vue

打开./runtime/index

import Vue from 'core/index'
 
Vue.prototype.$mount = function (
 el?: string | Element,
 hydrating?: boolean
): Component {
 el = el && inBrowser ? query(el) : undefined
 return mountComponent(this, el, hydrating)
}
export default Vue

在vue原型上添加了mount方法

处理了devtools,没有安装提醒安装devtools

给了这句提示dev环境提示

You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html

platforms目录夹讲解完毕

core目录

打开core/instance/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

先执行的是initMixin(Vue)

打开init

export function initMixin (Vue) {
 Vue.prototype._init = function (options?: Object) {
  const vm = this
  // a uid 
  vm._uid = uid++
   
  let startTag, endTag
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
   startTag = `vue-perf-start:${vm._uid}`
   endTag = `vue-perf-end:${vm._uid}`
   mark(startTag)
  }
 
  // a flag to avoid this being observed
  vm._isVue = true
  // 处理传入的options
  // merge options
  if (options && options._isComponent) {
   // optimize internal component instantiation
   // since dynamic options merging is pretty slow, and none of the
   // internal component options needs special treatment.
   initInternalComponent(vm, options)
  } else {
    // 传入的options,默认的options一起合并挂载到vm.$options上
   vm.$options = mergeOptions(
    resolveConstructorOptions(vm.constructor),
    options || {},
    vm
   )
  }
  /* istanbul ignore else */
  if (process.env.NODE_ENV !== 'production') {
   // 代理
   initProxy(vm)
  } else {
   vm._renderProxy = vm
  }
  // 生命周期
  initLifecycle(vm)
   // emit on 事件
  initEvents(vm)
  // 处理render vdom
  initRender(vm)
  callHook(vm, 'beforeCreate')
  // 处理Injections
  initInjections(vm) // resolve injections before data/props
  // 双向数据绑定,监听订阅
  initState(vm)
  initProvide(vm) // resolve provide after data/props
  callHook(vm, 'created')
   
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
   vm._name = formatComponentName(vm, false)
   mark(endTag)
   measure(`vue ${vm._name} init`, startTag, endTag)
  }
  // 渲染到dom
  if (vm.$options.el) {
   vm.$mount(vm.$options.el)
  }
 }
}

lifecycle

打开 lifecycle

export function callHook (vm: Component, hook: string) {
 // disable dep collection when invoking lifecycle hooks
 pushTarget()
 //执行对象的周期函数,周期函数最后被处理成数组
 const handlers = vm.$options[hook]
 const info = `${hook} hook`
 if (handlers) {
  for (let i = 0, j = handlers.length; i < j; i++) {
   invokeWithErrorHandling(handlers[i], vm, null, vm, info)
  }
 }
 if (vm._hasHookEvent) {
  vm.$emit('hook:' + hook)
 }
 popTarget()

callHook 的时候,是执行相应周期,开发者在周期函数里所写的

Events

initEvents实现了 emit on 等方法,请参考监听者订阅者模式,这里不详解

render
renderMixin函数
添加了 $nextTick _render 原型对象

$nextTick会在dom跟新后立即调用

nextTick(fn, this)是一个自执行函数

_render返回的是node的js数据,还不是dom

做了Vdom

initRender函数
给vm添加了_c和 $createElement用来渲染的方法

state

if (!(key in vm)) {
   proxy(vm, `_props`, key)
  }

给vue属性做代理,访问this.a可以得到this.data.a 的值

export function initState (vm: Component) {
 vm._watchers = []
 const opts = vm.$options
 if (opts.props) initProps(vm, opts.props)
 if (opts.methods) initMethods(vm, opts.methods)
 if (opts.data) {
  initData(vm)
 } else {
  observe(vm._data = {}, true /* asRootData */)
 }
 if (opts.computed) initComputed(vm, opts.computed)
 if (opts.watch && opts.watch !== nativeWatch) {
  initWatch(vm, opts.watch)
 }
}

给数据做监听

stateMixin函数

添加原型对象

Vue.prototype.$set = set
Vue.prototype.$delete = del

其他

src/compiler 做了编译处理

core/componetd 做了keep-alive

core/util 封装了通用方法

core/vdom vdom算法

以上整体架构分析完毕

实例讲解vue源码架构

Javascript 相关文章推荐
15 个 JavaScript Web UI 库
May 19 Javascript
JavaScript中setMonth()方法的使用详解
Jun 11 Javascript
JS闭包、作用域链、垃圾回收、内存泄露相关知识小结
May 16 Javascript
Javascript中常用类型的格式化方法小结
Dec 26 Javascript
JavaScript中值类型和引用类型的区别
Feb 23 Javascript
vue2笔记 — vue-router路由懒加载的实现
Mar 03 Javascript
jQuery实现图片滑动效果
Mar 08 Javascript
详解AngularJS用Interceptors来统一处理HTTP请求和响应
Jun 08 Javascript
Javascript(es2016) import和require用法和区别详解
Aug 11 Javascript
详解JavaScript 新语法之Class 的私有属性与私有方法
Apr 23 Javascript
微信小程序API—获取定位的详解
Apr 30 Javascript
vue中封装axios并实现api接口的统一管理
Dec 25 Vue.js
详解Node.js amqplib 连接 Rabbit MQ最佳实践
Jan 24 #Javascript
JavaScript私有变量实例详解
Jan 24 #Javascript
小程序从手动埋点到自动埋点的实现方法
Jan 24 #Javascript
JavaScript递归函数定义与用法实例分析
Jan 24 #Javascript
jQuery实现当拉动滚动条到底部加载数据的方法分析
Jan 24 #jQuery
vue结合element-ui使用示例
Jan 24 #Javascript
VUE+Element环境搭建与安装的方法步骤
Jan 24 #Javascript
You might like
PHP5 面向对象程序设计
2008/02/13 PHP
MySql 按时间段查询数据方法(实例说明)
2008/11/02 PHP
一个php Mysql类 可以参考学习熟悉下
2009/06/21 PHP
PHP获取文件绝对路径的代码(上一级目录)
2011/05/29 PHP
ThinkPHP CURD方法之page方法详解
2014/06/18 PHP
Discuz不使用插件实现简单的打赏功能
2019/03/21 PHP
JS实现在页面随时自定义背景颜色的方法
2015/02/27 Javascript
JS控制表单提交的方法
2015/07/09 Javascript
让你一句话理解闭包(简单易懂)
2016/06/03 Javascript
jquery 抽奖小程序实现代码
2016/10/12 Javascript
AngularJS2中一种button切换效果的实现方法(二)
2017/03/27 Javascript
javascript数组定义的几种方法
2017/10/06 Javascript
vue.js仿hover效果的实现方法示例
2019/01/28 Javascript
一起写一个即插即用的Vue Loading插件实现
2019/10/31 Javascript
如何通过JS实现转码与解码
2020/02/21 Javascript
JS如何判断对象是否包含某个属性
2020/08/29 Javascript
通过实例浅析Python对比C语言的编程思想差异
2015/08/30 Python
Python Socket传输文件示例
2017/01/16 Python
Python 数据结构之堆栈实例代码
2017/01/22 Python
Python运维之获取系统CPU信息的实现方法
2018/06/11 Python
Python的argparse库使用详解
2018/10/09 Python
Python中实现输入超时及如何通过变量获取变量名
2020/01/18 Python
Python操作注册表详细步骤介绍
2020/02/05 Python
java关于string最常出现的面试题整理
2021/01/18 Python
CSS3 制作旋转的大风车(充满童年回忆)
2013/01/30 HTML / CSS
铭立家具面试题
2012/12/06 面试题
2014年五四青年节活动方案
2014/03/29 职场文书
房地产开发项目建议书
2014/05/16 职场文书
科级干部群众路线教育实践活动个人对照检查材料
2014/09/19 职场文书
离婚协议书样本
2015/01/26 职场文书
白鹤梁导游词
2015/02/06 职场文书
教师廉洁自律个人总结
2015/02/10 职场文书
西游记读书笔记
2015/06/25 职场文书
2015年环境监察工作总结
2015/07/23 职场文书
Redis做数据持久化的解决方案及底层原理
2021/07/15 Redis
一次项目中Thinkphp绕过禁用函数的实战记录
2021/11/17 PHP