实例讲解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 相关文章推荐
javascript 二分法(数组array)
Apr 24 Javascript
初学js 新节点的创建 删除 的步骤
Jul 04 Javascript
Javascript的数组与字典用法与遍历对象的属性技巧
Nov 07 Javascript
js与运算符和或运算符的妙用
Feb 14 Javascript
jQuery CSS()方法改变现有的CSS样式
Aug 20 Javascript
后台获取ZTREE选中节点的方法
Feb 12 Javascript
JavaScript常用脚本汇总(三)
Mar 04 Javascript
JavaScript数组前面插入元素的方法
Apr 06 Javascript
使用Bootstrap + Vue.js实现表格的动态展示、新增和删除功能
Nov 27 Javascript
解决vue 项目引入字体图标报错、不显示等问题
Sep 01 Javascript
JQuery Ajax执行跨域请求数据的解决方案
Dec 10 jQuery
React学习之JSX与react事件实例分析
Jan 06 Javascript
详解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
PHP中cookies使用指南
2007/03/16 PHP
PHP高自定义性安全验证码代码
2011/11/27 PHP
js玩一玩WSH吧
2007/02/23 Javascript
左侧是表头的JS表格控件(自写,网上没有的)
2013/06/04 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 简史
2015/01/09 Javascript
javascript 动态创建表格的2种方法总结
2015/03/04 Javascript
jQuery Ajax File Upload实例源码
2016/12/12 Javascript
js简易版购物车功能
2017/06/17 Javascript
vue-router 路由基础的详解
2017/10/17 Javascript
js定时器+简单的动画效果实例
2017/11/10 Javascript
基于jQuery Ajax实现下拉框无刷新联动
2017/12/06 jQuery
vue指令只能输入正数并且只能输入一个小数点的方法
2018/06/08 Javascript
JS正则表达式常见用法实例详解
2018/06/19 Javascript
vue-router重定向和路由别名的使用讲解
2019/01/19 Javascript
手动实现vue2.0的双向数据绑定原理详解
2021/02/06 Vue.js
[00:32]2018DOTA2亚洲邀请赛EG出场
2018/04/03 DOTA
[01:16:01]VGJ.S vs Mski Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
[01:07:41]IG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
python通过pil将图片转换成黑白效果的方法
2015/03/16 Python
自己使用总结Python程序代码片段
2015/06/02 Python
python语言使用技巧分享
2016/05/31 Python
Python提取支付宝和微信支付二维码的示例代码
2019/02/15 Python
python三方库之requests的快速上手
2019/03/04 Python
详解PyCharm安装MicroPython插件的教程
2019/06/24 Python
Python实现K折交叉验证法的方法步骤
2019/07/11 Python
python监控nginx端口和进程状态
2019/09/06 Python
Django 设置多环境配置文件载入问题
2020/02/25 Python
Python爬取股票信息,并可视化数据的示例
2020/09/26 Python
德国排名第一的主题公园门票网站:Attraction Tickets Direct
2019/09/09 全球购物
社区端午节活动方案
2014/01/28 职场文书
最经典的大学生职业生涯规划范文
2014/03/05 职场文书
《金孔雀轻轻跳》教学反思
2014/04/20 职场文书
爱情保证书
2015/01/17 职场文书
岗位职责范本大全
2015/02/26 职场文书
地球上的星星观后感
2015/06/02 职场文书
建筑工程催款函
2015/06/24 职场文书