Vue2.0源码学习#0

作者: 苏星河 | 来源:发表于2016-09-07 03:34 被阅读990次

    近来没什么事,准备把Vue的源码通读一遍,2.0中加入了Serve-Side-Render、Virtual-Dom等新特性,看一看实现原理,顺便记录一下学习的过程,毕竟好记性不如烂笔头。

    作为源码解读系列第一篇文章,先从整个框架的入口开始看吧。Vue使用了部分ES6语法,比如module机制。

    import config from './config'
    //加载初始全局API
    import { initGlobalAPI } from './global-api/index'
    //类的初始化入口
    import Vue from './instance/index'
    
    initGlobalAPI(Vue)
    //在Vue类的原型上定义$isServer属性,用于判断是否支持服务端渲染
    //这样在Vue实例上调用vue.$isServer就可以知道是否开启了SSR
    //关于Object.defineProperty,这是一个ES5的方法,可以直接在对象上定义属性
    //Vue的数据绑定机制就是用的Object.defineProperty,这也是Vue不支持IE8及以下版本的原因
    //将data对象的属性转成getter和setter,具体原理见http://cn.vuejs.org/guide/reactivity.html
    Object.defineProperty(Vue.prototype, '$isServer', {
      get: () => config._isServer
    })
    //定义Vue版本号
    Vue.version = '2.0.0-rc.4'
    
    export default Vue
    

    以下就是config的源码

    //Vue使用了Flow做静态类型检查
    //Flow可以在代码运行前检查出参数、返回值、变量等类型异常
    //方便我们在代码运行前进行部分debug
    /* @flow */
    import { no, noop } from 'shared/util'
    export type Config = {
      optionMergeStrategies: { [key: string]: Function };
      silent: boolean;
      devtools: boolean;
      errorHandler: ?Function;
      ignoredElements: ?Array<string>;
      keyCodes: { [key: string]: number };
      // platform
      isReservedTag: (x?: string) => boolean;
      isUnknownElement: (x?: string) => boolean;
      getTagNamespace: (x?: string) => string | void;
      mustUseProp: (x?: string) => boolean;
      // internal
      _assetTypes: Array<string>;
      _lifecycleHooks: Array<string>;
      _maxUpdateCount: number;
      _isServer: boolean;
    }
    const config: Config = {
      optionMergeStrategies: Object.create(null),
      //是否显示warning,默认显示
      silent: false,
      //是否启动devtool
      devtools: process.env.NODE_ENV !== 'production',
      errorHandler: null,
      ignoredElements: null,
      keyCodes: Object.create(null),
      isReservedTag: no,
      isUnknownElement: no,
      getTagNamespace: noop,
      mustUseProp: no,
     //组件的默认类型
      _assetTypes: [
        'component',
        'directive',
        'filter'
      ],
     //定义组件的各种生命周期
      _lifecycleHooks: [
        'beforeCreate',
        'created',
        'beforeMount',
        'mounted',
        'beforeUpdate',
        'updated',
        'beforeDestroy',
        'destroyed',
        'activated',
        'deactivated'
      ],
     //规定组件在一次刷新中的最大循环更新次数
      _maxUpdateCount: 100,
      //判断全局环境是否为server
      _isServer: process.env.VUE_ENV === 'server'
    }
    export default config
    
    

    再来看Vue实例由哪些部分构成,这部分代码在src/instance,这个文件夹下有events.js,init.js,lifecycle.js,proxy.js,render.js,state.js`等文件,可以看到,一个Vue instance由这几部分构成。为了将这些模块组织在一起,Vue使用了Mixin模式。以下是index.js的代码:

    import { initMixin } from './init'
    import { stateMixin } from './state'
    import { renderMixin } from './render'
    import { eventsMixin } from './events'
    import { lifecycleMixin } from './lifecycle'
    
    function Vue (options) {
      this._init(options)
    }
    
    initMixin(Vue)
    stateMixin(Vue)
    eventsMixin(Vue)
    lifecycleMixin(Vue)
    renderMixin(Vue)
    
    export default Vue
    

    这里的Mixin利用了每个JavaScript对象都有一个原型,通过原型可以继承更多的属性,实现Vue类上方法的重用。在每个mixin方法中,将Vue类作为参数传递进去,并在其原型上定义各种内置方法。以eventsMixin方法为例:

    //为了说明,这里是其简化版
    export function eventsMixin (Vue: Class<Component>) {
      //实现事件绑定的方法,将其添加到原型上
      Vue.prototype.$on = function (event: string, fn: Function): Component {
        const vm: Component = this
       //支持绑定多个事件
        ;(vm._events[event] || (vm._events[event] = [])).push(fn)
        return vm
      }
    

    总结:

    1. Vue中大量使用Object.property,包括利用它生成访问器,实现数据绑定。
    2. Vue使用了Flow做静态类型检查,有助于提前发现bug
    3. 实现Vue类的过程中使用了Mixin这种设计模式,基于JavaScript原型继承的特性,可以方便的扩展Vue实例的功能。

    参考链接:
    Object.defineProperty()
    Flow | A Static Type Checker For JavaScript

    相关文章

      网友评论

      • RockerLau:期待#1、#2...
        苏星河: @Beyond_Xiang 😂有点尴尬……准备寒假有空的话再出新的文章,谢谢关注

      本文标题:Vue2.0源码学习#0

      本文链接:https://www.haomeiwen.com/subject/rwhjettx.html