Vue源码笔记本(一)

(该文章对src/core/instance下的文件的代码功能做了注解,便于大家在看源码过程中快速理解)

入口文件 src/core/instance/index.js 中可以看到

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

Vue的构造函数在此, 然后通过mixin的方式将

  • 数据方法等特性处理(state)
  • 事件处理(events)
  • 生命周期(lifecycle)
  • 渲染函数(render)

的相关的方法挂到Vue的原型上去。

1.init

挂上了_init 方法,没错就是 构造函数当中调用的_init方法。

这里做了一些参数处理,其中作者在参数对象赋值的时候,用一个个赋值代替列举赋值来提升性能。 这样注释的: // doing this because it's faster than dynamic enumeration.

然后就是依次执行以下方法,包括各个init函数和触发钩子

 / istanbul ignore else /
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initState(vm)
    callHook(vm, 'created')
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }

2.state

initState一共做了如下操作

 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) initWatch(vm, opts.watch)

initProps和initData的处理类似:

initProps做了类型检验,做了defineReactive就是响应式处理;

initData做了函数处理(data是对象或者函数),然后检查key是否与props重复,还检查了key是否$ 或者 _ 开头,这是vue内部使用, 如果你的key以此开头,你就会拿不到你的key了(这个好像没看到说明,感觉可以提示下)

然后做了个proxy,把用户参数props和data分别代理到 _props 和 _data 这2个内部属性,用户访问其实访问到了_props和_data下。

initMethods 这个就是把methods内部的函数bind到实例然后挂到实例

initWatch 通过遍历然后执行$watch方法来处理

initComputed 遍历为创建一个 Watcher 实例,然后放到_computedWatchers

(响应式相关后续再展开)

stateMixin 混入方法挂了$data,$props,$set,$delete等让数据操作指向_data 和 _props,然后挂了$watch 方法

3.events

挂载$on,$once,$off,$emit 四个方法

事件句柄都保存在 _events 这个属性里,在$on方法里做了个处理,判断该实例是否有使用生命周期的hook,如果没有_hasHookEvent这个值是false,然后在lifecycle的callHook方法里将不会$emit生命周期hook,是一个性能优化。

4.lifecycle

在原型上挂上 _mount 方法,这个比较重要, $mount 用的就是方法, ($mount在上面的init函数被调用)这个方法运行的时候需要用到render函数里了,没有会报错(关于这点,vue会把template或者el里的html模版最终转成render函数,一般如果我们用vue-loader开发,已经把template里的内容转成了render函数,所以最后打包出来的不会含有转化template的功能代码),render函数返回的是一个vnode,下面贴个_mount部分代码:

 callHook(vm, 'beforeMount')
    vm._watcher = new Watcher(vm, function updateComponent () {
      vm._update(vm._render(), hydrating)
    }, noop)
    hydrating = false
    // manually mounted instance, call mounted on self
    // mounted is called for render-created child components in its inserted hook
    if (vm.$vnode == null) {
      vm._isMounted = true
      callHook(vm, 'mounted')
    }

这里可以看到2个生命周期了

_update 方法开始去做dom更新了,看_update方法

一开始用_isMounted判断是否触发beforeUpdate钩子,因为第一次插入dom也是调用这个方法,但是不应该触发beforeUpdate

然后就去调用 patch 方法去做diff 然后更新dom了。(vnode以后再看)

另外,还挂载了$forceUpdate和$destroy 这2个方法

5.render

先挂载了 $nextTick 方法.

然后在renderMixin函数内往原型挂载了_render 方法(在instancei 下有个render-helpers文件夹里面有处理render相关的工具函数供调用)这个方法做了slot相关的操作,然后调用render函数拿到vnode ( render 相关的需要具体展开)

这里有个_renderProxy ,在非生产环境下做了proxy,看 proxy.js ,就是在访问实例属性的时候,访问不存在的属性的时候给予提示.

以上。

时间: 2024-11-03 16:00:09

Vue源码笔记本(一)的相关文章

Vue.js源码(1):Hello World的背后

下面的代码会在页面上输出Hello World,但是在这个new Vue()到页面渲染之间,到底发生了什么.这篇文章希望通过最简单的例子,去了解Vue源码过程.这里分析的源码版本是Vue.version = '1.0.20' <div id="mountNode">{{message}}</div>   var vm = new Vue({      el: '#mountNode',      data: function () {          retu

vue从使用到源码实现教程详解_javascript技巧

搭建环境 项目github地址 项目中涉及了json-server模拟get请求,用了vue-router: 关于Vue生命周期以及vue-router钩子函数详解 生命周期 1.0版本 1.哪些生命周期接口 init Created beforeCompile Compiled Ready Attatched Detached beforeDestory destoryed 2.执行顺序 1. 不具有keep-alive 进入: init->create->beforeCompile->

vue2.0源码分析之理解响应式架构

分享前啰嗦 我之前介绍过vue1.0如何实现observer和watcher.本想继续写下去,可是vue2.0横空出世..所以 直接看vue2.0吧.这篇文章在公司分享过,终于写出来了.我们采用用最精简的代码,还原vue2.0响应式架构实现 以前写的那篇 vue 源码分析之如何实现 observer 和 watcher可以作为本次分享的参考. 不过不看也没关系,但是最好了解下Object.defineProperty 本文分享什么 理解vue2.0的响应式架构,就是下面这张图 顺带介绍他比rea

Vue.js源码(2):初探List Rendering

下面例子来自官网,虽然看上去就比Hello World多了一个v-for,但是内部多了好多的处理过程.但是这就是框架,只给你留下最美妙的东西,让生活变得简单. <div id="mountNode">      <ul>          <li v-for="todo in todos">            {{ todo.text }}          </li>      </ul>  <

knockout.js源码解析

简介 本文主要对源码和内部机制做较深如的分析,基础部分请参阅官网文档. knockout.js (以下简称 ko )是最早将 MVVM 引入到前端的重要功臣之一.目前版本已更新到 3 .相比同类主要有特点有: 双工绑定基于 observe 模式,性能高. 插件和扩展机制非常完善,无论在数据层还是展现层都能满足各种复杂的需求. 向下支持到IE6 文档.测试完备,社区较活跃. 入口 以下分析都将对照 github 上3.x的版本.有一点需要先了解:ko 使用 google closure compi

avalon.js源码解析

简介 avalon是国内 司徒正美 写的MVVM框架,相比同类框架它的特点是: 使用 observe 模式,性能高. 将原始对象用object.defineProperty重写,不需要用户像用knockout时那样显示定义各种属性. 对低版本的IE使用了VBScript来兼容,一直兼容到IE6. 需要看基础介绍的话建议直接看司徒的博客.在网上搜了一圈,发现已经有了avalon很好的源码分析,这里也推荐一下:地址. avalon在圈子里一直被诟病不够规范的问题,请各位不必再留言在我这里,看源码无非

Microsoft Visual Studio与Firefly 一直提示加载项目,更新源码状态问题

        笔记本一开始安装的是vs2010,由于近期开发要用vs2008与vs2005于是今天又把2008.2005安装上了,但在打开项目的时候,先是提示加载项目文件,然后一直提示更新源码状态,很慢很慢的,之前只有vs2010的时候,打开是很快的,现在不管是用2008.2005.2010就没有一个快的,源码管理用的是firefly,有人知道为什么会出现这种情况吗?         截图: 解决方法:        第一步:打开<网络与共享中心>,找打<更改适配器设置>如下图:

Android编程动态加载布局实例详解【附demo源码】_Android

本文实例讲述了Android编程动态加载布局的方法.分享给大家供大家参考,具体如下: 由于前段时间项目需要,需要在一个页面上加载根据不同的按钮加载不同的布局页面,当时想到用 tabhot .不过美工提供的界面图完全用不上tabhot ,所以想到了动态加载的方法来解决这一需求.在这里我整理了一下,写了一个 DEMO 希望大家以后少走点弯路. 首先,我们先把界面的框架图画出来,示意图如下: 中间白色部门是一个线性布局文件,我喜欢在画图的时候用不同的颜色将一块布局标示出来,方便查看.布局文件代码如下:

jQuery自定义动画函数实例详解(附demo源码)_jquery

本文实例讲述了jQuery自定义动画函数完整实现技巧.分享给大家供大家参考,具体如下: 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/jquery-zdy-dh-move-style-demo/ 具体代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.d