实例讲解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 入门基础学习
Mar 10 Javascript
javascript delete 使用示例代码
Mar 29 Javascript
JavaScript基础篇之变量作用域、传值、传址的简单介绍与实例
Jun 29 Javascript
jquery实现的鼠标下拉滚动置顶效果
Jul 24 Javascript
jquery复选框多选赋值给文本框的方法
Jan 27 Javascript
jQuery制作仿Mac Lion OS滚动条效果
Feb 10 Javascript
JavaScript动态插入CSS的方法
Dec 10 Javascript
JS实现侧边栏鼠标经过弹出框+缓冲效果
Mar 29 Javascript
VUE中v-model和v-for指令详解
Jun 23 Javascript
JS删除数组里的某个元素方法
Feb 03 Javascript
jQuery实现当拉动滚动条到底部加载数据的方法分析
Jan 24 jQuery
vue中实现点击空白区域关闭弹窗的两种方法
Dec 30 Vue.js
详解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
一个简单计数器的源代码
2006/10/09 PHP
兼容firefox,chrome的网页灰度效果
2011/08/08 PHP
PHP 正则表达式之正则处理函数小结(preg_match,preg_match_all,preg_replace,preg_split)
2012/10/05 PHP
关于php内存不够用的快速解决方法
2013/10/26 PHP
Yii中Model(模型)的创建及使用方法
2015/12/28 PHP
利用PHP将图片转换成base64编码的实现方法
2016/09/13 PHP
js 获取Listbox选择的值的代码
2010/04/15 Javascript
JavaScript实现找出数组中最长的连续数字序列
2014/09/03 Javascript
jQuery中[attribute*=value]选择器用法实例
2014/12/31 Javascript
js判断一个字符串是否包含一个子串的方法
2015/01/26 Javascript
详解关于微信setData回调函数中的坑
2019/02/18 Javascript
jquery实现下载图片功能
2019/07/18 jQuery
JSX在render函数中的应用详解
2019/09/04 Javascript
JS运算符简单用法示例
2020/01/19 Javascript
在Chrome DevTools中调试JavaScript的实现
2020/04/07 Javascript
vue实现购物车结算功能
2020/06/18 Javascript
Vue实现简单购物车功能
2020/12/13 Vue.js
[33:39]DOTA2上海特级锦标赛C组小组赛#2 LGD VS Newbee第二局
2016/02/27 DOTA
Python中使用插入排序算法的简单分析与代码示例
2016/05/04 Python
Python爬虫DOTA排行榜爬取实例(分享)
2017/06/13 Python
Python cookbook(数据结构与算法)实现对不原生支持比较操作的对象排序算法示例
2018/03/15 Python
pip命令无法使用的解决方法
2018/06/12 Python
tensorflow 中对数组元素的操作方法
2018/07/27 Python
Python django框架应用中实现获取访问者ip地址示例
2019/05/17 Python
Python3.6+selenium2.53.6自动化测试_读取excel文件的方法
2019/09/06 Python
基于python+selenium的二次封装的实现
2020/01/06 Python
欧洲第一的摇滚和金属乐队服装网站:EMP
2017/10/26 全球购物
Cult Gaia官网:美国生活方式品牌
2019/08/16 全球购物
法律专业自我鉴定
2013/10/03 职场文书
市场开发与营销专业求职信
2013/12/31 职场文书
旅游网创业计划书
2014/01/31 职场文书
初中生评语大全
2014/04/24 职场文书
2014乡镇班子个人对照检查材料思想汇报
2014/09/26 职场文书
python中的装饰器该如何使用
2021/06/18 Python
C#连接ORACLE出现乱码问题的解决方法
2021/10/05 Oracle
JavaScript流程控制(分支)
2021/12/06 Javascript