实例讲解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 相关文章推荐
任意位置显示html菜单
Feb 01 Javascript
8个实用的jQuery技巧
Mar 04 Javascript
JavaScript中的Function函数
Aug 27 Javascript
自定义刻度jQuery进度条及插件
Sep 02 Javascript
理解javascript对象继承
Apr 17 Javascript
jQuery ajax的功能实现方法详解
Jan 06 Javascript
vue如何从接口请求数据
Jun 22 Javascript
微信小程序tabBar模板用法实例分析【附demo源码下载】
Nov 28 Javascript
jQuery解析json格式数据示例
Sep 01 jQuery
Vue render函数实战之实现tabs选项卡组件
Apr 22 Javascript
element-ui上传一张图片后隐藏上传按钮功能
May 22 Javascript
JavaScript实现浏览器网页自动滚动并点击的示例代码
Dec 05 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根据日期判断星座的函数分享
2014/02/13 PHP
PHP数字金额转换成中文大写显示
2019/01/05 PHP
phpstudy2020搭建站点的实现示例
2020/10/30 PHP
JavaScript 常用函数
2009/12/30 Javascript
10款新鲜出炉的 jQuery 插件(Ajax 插件,有幻灯片、图片画廊、菜单等)
2011/06/08 Javascript
js替换字符串的所有示例代码
2013/07/23 Javascript
多种方法判断Javascript对象是否存在
2013/09/22 Javascript
JSON无限折叠菜单编写实例
2013/12/16 Javascript
使用jquery实现放大镜效果
2014/09/02 Javascript
JavaScript中用于生成随机数的Math.random()方法
2015/06/15 Javascript
JavaScript下的时间格式处理函数Date.prototype.format
2016/01/27 Javascript
jQuery Ajax 加载数据时异步显示加载动画
2016/08/01 Javascript
js实现无缝滚动图(可控制当前滚动的方向)
2017/02/22 Javascript
nodejs入门教程二:创建一个简单应用示例
2017/04/24 NodeJs
json2.js 入门教程之使用方法与实例分析
2017/09/14 Javascript
微信小程序下拉框组件使用方法详解
2018/12/28 Javascript
详解如何搭建mpvue框架搭配vant组件库的小程序项目
2019/05/16 Javascript
小程序api实现promise封装过程解析
2019/11/21 Javascript
python网页请求urllib2模块简单封装代码
2014/02/07 Python
Python动刷新抢12306火车票的代码(附源码)
2018/01/24 Python
python程序快速缩进多行代码方法总结
2019/06/23 Python
Python qqbot 实现qq机器人的示例代码
2019/07/11 Python
python异常处理try except过程解析
2020/02/03 Python
python对Excel的读取的示例代码
2020/02/14 Python
Python使用GitPython操作Git版本库的方法
2020/02/29 Python
解决Django Haystack全文检索为空的问题
2020/05/19 Python
学生打架检讨书1000字
2014/01/16 职场文书
给领导的检讨书
2014/02/16 职场文书
报纸媒体创意广告词
2014/03/17 职场文书
学校志愿者活动总结
2014/06/27 职场文书
艺术学院毕业生自荐信
2014/07/05 职场文书
祖国在我心中演讲稿200字
2014/08/28 职场文书
2015年基层党建工作总结
2015/05/14 职场文书
追讨欠款律师函
2015/05/27 职场文书
家长意见书
2015/06/04 职场文书
nginx之内存池的实现
2022/06/28 Servers