美文网首页
vue源码第一天

vue源码第一天

作者: e80c3fbed5b2 | 来源:发表于2020-06-18 22:59 被阅读0次

    vue源码目录结构

    简单,干净,明了,清晰

    src
    ├── compiler        # 编译相关 
    ├── core            # 核心代码 
    ├── platforms       # 不同平台的支持
    ├── server          # 服务端渲染
    ├── sfc             # .vue 文件解析
    ├── shared          # 共享代码
    

    vue是什么?

    import { initMixin } from './init'
    import { stateMixin } from './state'
    import { renderMixin } from './render'
    import { eventsMixin } from './events'
    import { lifecycleMixin } from './lifecycle'
    import { warn } from '../util/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
    

    vue是一个function类,为什么不用es6的class呢?因为下面有多个xxMixin(Vue)的调用,并把Vue当作参数传入,它们的作用都是为Vue的prototype扩展一些方法,这些方法都是Vue按功能将各个扩展分散到各个模块中去实现,而使用class是难以实现的。

    全局 initGlobalAPI

    Vue在整个初始化的过程中,除了给它的原型扩展方法,还会给Vue本身扩展全局的静态方法;

    在Vue官网上关于全局的api在这个下main都能找到

    /* @flow */
    
    import config from '../config'
    import { initUse } from './use'
    import { initMixin } from './mixin'
    import { initExtend } from './extend'
    import { initAssetRegisters } from './assets'
    import { set, del } from '../observer/index'
    import { ASSET_TYPES } from 'shared/constants'
    import builtInComponents from '../components/index'
    import { observe } from 'core/observer/index'
    
    import {
      warn,
      extend,
      nextTick,
      mergeOptions,
      defineReactive
    } from '../util/index'
    
    export function initGlobalAPI (Vue: GlobalAPI) {
      // config
      const configDef = {}
      configDef.get = () => config
      if (process.env.NODE_ENV !== 'production') {
        configDef.set = () => {
          warn(
            'Do not replace the Vue.config object, set individual fields instead.'
          )
        }
      }
      Object.defineProperty(Vue, 'config', configDef)
    
      // exposed util methods.
      // NOTE: these are not considered part of the public API - avoid relying on
      // them unless you are aware of the risk.
      Vue.util = {
        warn,
        extend,
        mergeOptions,
        defineReactive
      }
    
      Vue.set = set
      Vue.delete = del
      Vue.nextTick = nextTick
    
      // 2.6 explicit observable API
      Vue.observable = <T>(obj: T): T => {
        observe(obj)
        return obj
      }
    
      Vue.options = Object.create(null)
      ASSET_TYPES.forEach(type => {
        Vue.options[type + 's'] = Object.create(null)
      })
    
      // this is used to identify the "base" constructor to extend all plain-object
      // components with in Weex's multi-instance scenarios.
      Vue.options._base = Vue
    
      extend(Vue.options.components, builtInComponents)
    
      initUse(Vue)
      initMixin(Vue)
      initExtend(Vue)
      initAssetRegisters(Vue)
    }
    

    数据驱动

    Vue和react的核心思想都是数据驱动,而什么是数据驱动呢?所谓的数据驱动就是不直接操作dom,而是通过数据的修改来改变视图的状态。这样做的好处在于避免了直接操作dom,使代码更加的简洁易懂,同时避免了浏览器的重绘重排等性能的消耗,能够更快(不是说直接操作dom慢,而是这样更快)。所以当交互复杂时,只关心数据的修改使得代码的逻辑更加清晰,性能也更好。那么关于dom,vue是怎么将数据和模板渲染成dom的呢?

    new Vue发生了什么

    之前提到,vue的本质是一个function类,通过new来实例化。

    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)
    }
    

    从这里可以看出,Vue只能通过new来实例化,如果不是生产环境并且不在Vue原型链上,那么就会warn应该使用new 关键字;

    当是通过new关键字来实例化一个对象的时候,vue会执行Vue原型链上的_init方法来初始化vue,并将节点(字符串)作为参数传入(options是new Vue('#app')时传入的字符串);在_init下会初始化生命周期、事件、render、props、data等

    vm._self = vm
      initLifecycle(vm)
      initEvents(vm)
      initRender(vm)
      callHook(vm, 'beforeCreate')
      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)
      }
    
      if (vm.$options.el) {
        vm.$mount(vm.$options.el)
      }
    

    在最后,如果有el属性,那么就调用vm.$mount方法挂载vm,挂载vm的最终目的就是为了将模板渲染成最终的DOM;

    明天计划:Vue实例挂载的实现。

    相关文章

      网友评论

          本文标题:vue源码第一天

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