实例讲解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 相关文章推荐
Web 前端设计模式--Dom重构 提高显示性能
Oct 22 Javascript
浏览器页面区域大小的js获取方法
Sep 21 Javascript
21个值得收藏的Javascript技巧
Feb 04 Javascript
Jquery仿IGoogle实现可拖动窗口示例代码
Aug 22 Javascript
seajs加载jquery时提示$ is not a function该怎么解决
Oct 23 Javascript
微信小程序 教程之wxapp视图容器 swiper
Oct 19 Javascript
微信小程序 循环及嵌套循环的使用总结
Sep 26 Javascript
Bootstrap4如何定制自己的颜色和风格
Feb 26 Javascript
Angularjs Promise实例详解
Mar 15 Javascript
ElementUI Tag组件实现多标签生成的方法示例
Jul 08 Javascript
深入理解令牌认证机制(token)
Aug 22 Javascript
javascript this指向相关问题及改变方法
Nov 19 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微信开发之关键词回复功能
2018/06/13 PHP
Yii框架连表查询操作示例
2019/09/06 PHP
laravel csrf排除路由,禁止,关闭指定路由的例子
2019/10/21 PHP
javascript 定义初始化数组函数
2009/09/07 Javascript
jquery使用ColorBox弹出图片组浏览层实例演示
2013/03/14 Javascript
在js中判断checkboxlist(.net控件客户端id)是否有选中
2013/04/11 Javascript
javascript用户注册提示效果的简单实例
2013/08/17 Javascript
下拉列表select 由左边框移动到右边示例
2013/12/04 Javascript
javascript常用代码段搜集
2014/12/04 Javascript
浅谈JavaScript 覆盖原型以及更改原型
2016/08/31 Javascript
微信小程序 数据封装,参数传值等经验分享
2017/01/09 Javascript
纯js实现图片匀速淡入淡出效果
2017/08/22 Javascript
vue+swiper实现侧滑菜单效果
2017/12/28 Javascript
vue实现动态添加数据滚动条自动滚动到底部的示例代码
2018/07/06 Javascript
ElementUI Tag组件实现多标签生成的方法示例
2019/07/08 Javascript
原生js实现日历效果
2020/03/02 Javascript
[03:14]辉夜杯主赛事 12月25日每日之星
2015/12/26 DOTA
[01:16:16]DOTA2-DPC中国联赛定级赛 RNG vs Phoenix BO3第二场 1月8日
2021/03/11 DOTA
python list转dict示例分享
2014/01/28 Python
python开发之thread实现布朗运动的方法
2015/11/11 Python
关于Python面向对象编程的知识点总结
2017/02/14 Python
python截取两个单词之间的内容方法
2018/12/25 Python
Laravel+Dingo/Api 自定义响应的实现
2019/02/17 Python
Python将列表数据写入文件(txt, csv,excel)
2019/04/03 Python
python实现随机漫步方法和原理
2019/06/10 Python
python爬虫 urllib模块发起post请求过程解析
2019/08/20 Python
Python列表如何更新值
2020/05/27 Python
基于TensorFlow的CNN实现Mnist手写数字识别
2020/06/17 Python
使用Python项目生成所有依赖包的清单方式
2020/07/13 Python
pymongo insert_many 批量插入的实例
2020/12/05 Python
魔幻般冒泡背景的CSS3按钮动画
2016/02/27 HTML / CSS
详解基于 Canvas 手撸一个六边形能力图
2019/09/02 HTML / CSS
伯利陶器:Burleigh Pottery
2018/01/03 全球购物
函授毕业生的自我鉴定
2013/11/26 职场文书
遗嘱继承公证书
2014/04/09 职场文书
《泉水》教学反思
2014/04/11 职场文书