实例讲解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版代码高亮
Jun 26 Javascript
jQuery动画效果-fadeIn fadeOut淡入浅出示例代码
Aug 28 Javascript
Function.prototype.bind用法示例
Sep 16 Javascript
javascript实现的弹出层背景置灰-模拟(easyui dialog)
Dec 27 Javascript
运用JQuery的toggle实现网页加载完成自动弹窗
Mar 18 Javascript
jquery实现最简单的滑动菜单效果代码
Sep 12 Javascript
更靠谱的H5横竖屏检测方法(js代码)
Sep 13 Javascript
node.js实现回调的方法示例
Mar 01 Javascript
JavaScript原型继承_动力节点Java学院整理
Jun 30 Javascript
vue项目刷新当前页面的三种方法
Dec 04 Javascript
vue使用better-scroll实现滑动以及左右联动
Jun 30 Javascript
基于JS实现快速读取TXT文件
Aug 25 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对象克隆clone用法示例
2016/09/28 PHP
PHP严重致命错误处理:php Fatal error: Cannot redeclare class or function
2017/02/05 PHP
PHPUnit测试私有属性和方法功能示例
2018/06/12 PHP
javascript showModalDialog,open取得父窗口的方法
2010/03/10 Javascript
通过jquery还原含有rowspan、colspan的table的实现方法
2012/02/10 Javascript
window.event.keyCode兼容IE和Firefox实现js代码
2013/05/30 Javascript
Jquery倒计时源码分享
2014/05/16 Javascript
js闭包的用途详解
2014/11/09 Javascript
innerHTML在IE中报错解决方案
2014/12/15 Javascript
深入理解JavaScript系列(41):设计模式之模板方法详解
2015/03/04 Javascript
浅谈jquery.fn.extend与jquery.extend区别
2015/07/13 Javascript
基于Jquery+div+css实现弹出登录窗口(代码超简单)
2015/10/27 Javascript
Angular 根据 service 的状态更新 directive
2016/04/03 Javascript
有关jquery与DOM节点操作方法和属性记录
2016/04/15 Javascript
对象转换为原始值的实现方法
2016/06/06 Javascript
微信小程序 五星评分(包括半颗星评分)实例代码
2016/12/14 Javascript
JavaScript中数组常见操作技巧
2017/09/01 Javascript
webpack 单独打包指定JS文件的方法
2018/02/22 Javascript
Vue 理解之白话 getter/setter详解
2019/04/16 Javascript
关于vue里页面的缓存详解
2019/11/04 Javascript
python实现socket端口重定向示例
2014/02/10 Python
Python自动生产表情包
2017/03/17 Python
python实现大转盘抽奖效果
2019/01/22 Python
pyqt远程批量执行Linux命令程序的方法
2019/02/14 Python
Django保护敏感信息的方法示例
2019/05/09 Python
解决Python3 控制台输出InsecureRequestWarning问题
2019/07/15 Python
全网最细 Python 格式化输出用法讲解(推荐)
2021/01/18 Python
基于HTML5 Canvas:字符串,路径,背景,图片的详解
2013/05/09 HTML / CSS
Giglio德国网上精品店:奢侈品服装和配件
2016/09/23 全球购物
美国孩之宝玩具官网:Hasbro Pulse
2019/06/24 全球购物
史上最全面的Java面试题汇总!
2015/02/03 面试题
学历公证委托书
2014/04/09 职场文书
求职信名称怎么写
2014/05/26 职场文书
低碳生活的宣传标语
2014/06/23 职场文书
加强机关作风建设心得体会
2014/10/22 职场文书
Vue elementUI表单嵌套表格并对每行进行校验详解
2022/02/18 Vue.js