实例讲解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 相关文章推荐
jquery实现图片等比例缩放以及max-width在ie中不兼容解决
Mar 21 Javascript
判断ie的两种简单方法
Aug 12 Javascript
javascript获取元素CSS样式代码示例
Nov 28 Javascript
jQuery中的height innerHeight outerHeight区别示例介绍
Jun 15 Javascript
浅谈js的setInterval事件
Dec 05 Javascript
js定时器实例分享
Dec 20 Javascript
js实现定时进度条完成后切换图片
Jan 04 Javascript
vue-router配合ElementUI实现导航的实例
Feb 11 Javascript
一百行JS代码实现一个校验工具
Apr 30 Javascript
微信小程序获取用户信息并保存登录状态详解
May 10 Javascript
使用JS location实现搜索框历史记录功能
Dec 23 Javascript
Vue+Element自定义纵向表格表头教程
Oct 26 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下通过系统信号量加锁方式获取递增序列ID
2009/09/25 PHP
php错误提示failed to open stream: HTTP request failed!的完美解决方法
2011/06/06 PHP
YII模块实现绑定二级域名的方法
2014/07/09 PHP
PHP中imagick函数的中文解释
2015/01/21 PHP
thinkphp3.x中session方法的用法分析
2016/05/20 PHP
Ubuntu 16.04中Laravel5.4升级到5.6的步骤
2018/12/07 PHP
PHP结合Redis+MySQL实现冷热数据交换应用案例详解
2019/07/09 PHP
jQuery 入门级学习笔记及源码
2010/01/22 Javascript
JQuery模板插件 jquery.tmpl 动态ajax扩展
2011/11/10 Javascript
JQUERY 获取IFrame中对象及获取其父窗口中对象示例
2013/08/19 Javascript
qq悬浮代码(兼容各个浏览器)
2014/01/29 Javascript
JavaScript验证18位身份证号码最后一位正确性的实现代码
2014/08/07 Javascript
浅谈javascript中自定义模版
2015/01/29 Javascript
JS实现点击按钮获取页面高度的方法
2015/11/02 Javascript
轻松5句话解决JavaScript的作用域
2016/07/15 Javascript
Node.js Sequelize如何实现数据库的读写分离
2016/10/23 Javascript
@ResponseBody 和 @RequestBody 注解的区别
2017/03/08 Javascript
详解使用PM2管理nodejs进程
2017/10/24 NodeJs
详解vue-cli3多环境打包配置
2019/03/28 Javascript
ES6之Proxy的get方法详解
2019/10/11 Javascript
[46:59]完美世界DOTA2联赛PWL S2 GXR vs Ink 第二场 11.19
2020/11/20 DOTA
Python中 Lambda表达式全面解析
2016/11/28 Python
python编程使用selenium模拟登陆淘宝实例代码
2018/01/25 Python
python 通过xml获取测试节点和属性的实例
2018/03/31 Python
python 从文件夹抽取图片另存的方法
2018/12/04 Python
python 在指定范围内随机生成不重复的n个数实例
2019/01/28 Python
Python字符串通过'+'和join函数拼接新字符串的性能测试比较
2019/03/05 Python
美国照明、家居装饰和家具购物网站:Bellacor
2017/09/20 全球购物
仓库门卫岗位职责
2013/12/22 职场文书
个人安全生产承诺书
2014/05/22 职场文书
查摆问题自我剖析材料
2014/08/18 职场文书
行政工作试用期自我评价
2014/09/14 职场文书
入党积极分子批评与自我批评思想汇报
2014/09/14 职场文书
学生上课迟到检讨书
2015/01/01 职场文书
大学生就业意向书
2015/05/11 职场文书
python flask开发的简单基金查询工具
2021/06/02 Python