实例讲解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 Date对象使用总结
May 14 Javascript
做web开发 先学JavaScript
Dec 12 Javascript
jQuery获得指定元素坐标的方法
Apr 14 Javascript
javascript瀑布流布局实现方法详解
Feb 17 Javascript
AngularJS 自定义过滤器详解及实例代码
Sep 14 Javascript
JavaScript实现Fly Bird小游戏
Dec 15 Javascript
xmlplus组件设计系列之分隔框(DividedBox)(8)
May 02 Javascript
vue-loader教程介绍
Jun 14 Javascript
jQuery ajax仿Google自动提示SearchSuggess功能示例
Mar 28 jQuery
国内常用的js类库大全(CDN公共库)
Jun 24 Javascript
深度解读vue-resize的具体用法
Jul 08 Javascript
浅谈react useEffect闭包的坑
Jun 08 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 at(@)符号的用法简介
2009/07/11 PHP
探讨多键值cookie(php中cookie存取数组)的详解
2013/06/06 PHP
php获取文章上一页与下一页的方法
2014/12/01 PHP
Laravel模板引擎Blade中section的一些标签的区别介绍
2015/02/10 PHP
PHP的Yii框架使用中的一些错误解决方法与建议
2015/08/21 PHP
详解PHP字符串替换str_replace()函数四种用法
2017/10/13 PHP
JavaScript 变量基础知识
2009/11/07 Javascript
页面调用单个swf文件,嵌套出多个方法。
2011/11/21 Javascript
jQuery统计上传文件大小的方法
2015/01/24 Javascript
JavaScript中的toUTCString()方法使用详解
2015/06/12 Javascript
使用Chart.js图表库制作漂亮的响应式表单
2015/10/28 Javascript
jquery实现select选择框内容左右移动代码分享
2015/11/21 Javascript
jQuery简单设置文本框回车事件的方法
2016/08/01 Javascript
es6学习笔记之Async函数的使用示例
2017/05/11 Javascript
基于Particles.js制作超炫粒子动态背景效果(仿知乎)
2017/09/13 Javascript
vue axios整合使用全攻略
2018/05/24 Javascript
详解小程序循环require之坑
2019/03/08 Javascript
小程序卡片切换效果组件wxCardSwiper的实现
2020/02/13 Javascript
es6 super关键字的理解与应用实例分析
2020/02/15 Javascript
javascript 模块依赖管理的本质深入详解
2020/04/30 Javascript
vue-cli4.x创建企业级项目的方法步骤
2020/06/18 Javascript
Python创建xml的方法
2015/03/10 Python
pygame学习笔记(2):画点的三种方法和动画实例
2015/04/15 Python
Python 3中print函数的使用方法总结
2017/08/08 Python
pytorch中使用cuda扩展的实现示例
2020/02/12 Python
详解python中的lambda与sorted函数
2020/09/04 Python
彻底解决Python包下载慢问题
2020/11/15 Python
用CSS3打造HTML5的Logo(实现代码)
2016/06/16 HTML / CSS
教师找工作推荐信
2013/11/23 职场文书
会计电算化毕业生自荐信
2014/03/03 职场文书
国培计划培训感言
2014/03/11 职场文书
钳工实训报告总结
2014/11/04 职场文书
庆七一活动简报
2015/07/20 职场文书
春节随笔
2015/08/15 职场文书
MongoDB使用场景总结
2022/02/24 MongoDB
面试中老生常谈的MySQL问答集锦夯实基础
2022/03/13 MySQL