实例讲解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 复杂的嵌套环境中输出单引号和双引号
May 26 Javascript
用js实现层随着内容大小动态渐变改变 推荐
Dec 19 Javascript
extjs 的权限问题 要求控制的对象是 菜单,按钮,URL
Mar 09 Javascript
JQuery中$(document)是什么意思有什么作用
Jul 21 Javascript
JS实现弹出浮动窗口(支持鼠标拖动和关闭)实例详解
Aug 06 Javascript
javascript原生ajax写法分享
Apr 10 Javascript
利用jquery获取select下拉框的值
Nov 23 Javascript
vue router仿天猫底部导航栏功能
Oct 18 Javascript
vue父组件向子组件(props)传递数据的方法
Jan 02 Javascript
js+html5实现手机九宫格密码解锁功能
Jul 30 Javascript
js纯前端实现腾讯cos文件上传功能的示例代码
May 14 Javascript
javascript进阶篇深拷贝实现的四种方式
Jul 07 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
destoon公司主页模板风格的添加方法
2014/06/20 PHP
PHP 只允许指定IP访问(允许*号通配符过滤IP)
2014/07/08 PHP
PHP函数in_array()使用详解
2014/08/20 PHP
php一个文件搞定微信jssdk配置
2016/12/12 PHP
PHP使用文件锁解决高并发问题示例
2018/03/29 PHP
PHP PDOStatement::execute讲解
2019/01/31 PHP
Safari5中alert的无限循环BUG
2011/04/07 Javascript
如何通过javascript操作web控件的自定义属性
2013/11/25 Javascript
JS字符串截取函数实例
2013/12/27 Javascript
JS的get和set使用示例
2014/02/20 Javascript
JavaScript中的console.log()函数详细介绍
2014/12/29 Javascript
JS非Alert实现网页右下角“未读信息”效果弹窗
2015/09/26 Javascript
JS中artdialog弹出框控件之提交表单思路详解
2016/04/18 Javascript
简单掌握JavaScript中const声明常量与变量的用法
2016/05/21 Javascript
easyui combobox开启搜索自动完成功能的实例代码
2016/11/08 Javascript
Bootstrap学习笔记之进度条、媒体对象实例详解
2017/03/09 Javascript
JavaScript实现一个空中避难的小游戏
2017/06/06 Javascript
jQuery Pagination分页插件_动力节点Java学院整理
2017/07/17 jQuery
使用jquery DataTable和ajax向页面显示数据列表的方法
2018/08/09 jQuery
javascript实现图片轮播代码
2019/07/09 Javascript
React Native中ScrollView组件轮播图与ListView渲染列表组件用法实例分析
2020/01/06 Javascript
ES5和ES6中类的区别总结
2020/12/21 Javascript
[02:07]TI9显影之尘系列 - Vici Gaming
2019/08/20 DOTA
详解Python中的装饰器、闭包和functools的教程
2015/04/02 Python
初步解析Python中的yield函数的用法
2015/04/03 Python
python实现斐波那契数列的方法示例
2017/01/12 Python
详解python中字典的循环遍历的两种方式
2017/02/07 Python
python实现生命游戏的示例代码(Game of Life)
2018/01/24 Python
Lookfantastic德国官网:英国知名美妆购物网站
2017/06/11 全球购物
GafasWorld西班牙:购买太阳镜、眼镜和隐形眼镜
2019/09/08 全球购物
英国在线定制百叶窗网站:Swift Direct Blinds
2020/02/25 全球购物
小区推广策划方案
2014/06/06 职场文书
五一劳动节演讲稿
2014/09/12 职场文书
初中差生评语
2014/12/29 职场文书
2015年秋季小学开学标语
2015/07/16 职场文书
nginx常用命令放入shell脚本详解
2021/03/31 Servers