zoukankan      html  css  js  c++  java
  • 入口开始,解读Vue源码(一)-- 造物创世

    Why?

    网上现有的Vue源码解析文章一搜一大批,但是为什么我还要去做这样的事情呢?因为觉得纸上得来终觉浅,绝知此事要躬行

    然后平时的项目也主要是Vue,在使用Vue的过程中,也对其一些约定产生了一些疑问,可能官网上只会建议你这么做,但是核心实现我们可能并不知道。比如:

    • v-for key 是如何达到“就地复用”策略
    • 数组更新检测是如何完成的
    • set 为什么就能动态添加根级别的响应式属性
    • 为什么Vue可以跨平台支持weex,以及后来出现的mpvue
    • ...

    其次,很久没有更新内容了,之前对Vue源码也是有点研究,只不过没有很体系的记录,现在抽了点时间,做了一次基础的总结吧。一方面是因为想要克服自己的惰性,另一方面也是想重新温故一遍。

    What?

    一共分成了10个基础部分,后续还会继续记录。我们可以先看一下概览:

    然后我们来看一下基础的目录:

    入口开始,解读Vue源码(一)———— 造物创世

    入口开始,解读Vue源码(二)—— new Vue 的故事

    入口开始,解读Vue源码(三)—— initMixin 上篇

    入口开始,解读Vue源码(三)—— initMixin 下篇

    入口开始,解读Vue源码(四)—— 实现一个基础的 Vue 双向绑定

    入口开始,解读Vue源码(五)—— $mount 内部实现

    入口开始,解读Vue源码(六)—— $mount 内部实现 --- compile parse函数生成AST

    入口开始,解读Vue源码(七)—— $mount 内部实现 --- compile optimize标记节点

    入口开始,解读Vue源码(八)—— $mount 内部实现 --- compile generate 生成render函数

    入口开始,解读Vue源码(九)—— $mount 内部实现 --- render函数 --> VNode

    入口开始,解读Vue源码(十)—— $mount 内部实现 --- patch

    开篇:入口开始,解读Vue源码(一)-- 造物创世

    世间万物的起源来自于盘古的开天辟地,Vue 项目的起源,源于一次Vue的实例化:

    new Vue({
      el: ...,
      data: ...,
      ....
    })
    

    那么在这次实例化的过程中,究竟发生了哪些行为?让我们来一探究竟。打开Vue的源码文件,其核心代码在src/core目录下。下面我们从入口文件index.js开始进入:(刚开始看的时候,我们可能不太清楚每个引用方法的具体实现,不过没关系,我们可以自己根据他的命名来YY一下。)

    // src/core/index.js
    
    // 这里应该是我们 Vue 核心方法
    import Vue from './instance/index'
    // 根据命名,应该可以猜出这里是初始化一些全局API
    import { initGlobalAPI } from './global-api/index'
    // 根据命名,这里应该是获取一个Boolean类型的变量,来判断是不是ssr
    import { isServerRendering } from 'core/util/env'
    // 这里开始执行初始化全局变量
    initGlobalAPI(Vue)
    // 为Vue原型定义属性$isServer
    Object.defineProperty(Vue.prototype, '$isServer', {
      get: isServerRendering
    })
    // 为Vue原型定义属性$ssrContext
    Object.defineProperty(Vue.prototype, '$ssrContext', {
      get () {
        /* istanbul ignore next */
        return this.$vnode && this.$vnode.ssrContext
      }
    })
    
    Vue.version = '__VERSION__'
    
    export default Vue
    

    下面我们来一步步验证我们的猜测,首先找到core/instance/index文件,可以清晰的看到:

    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 Class,然后又调用了一系列init、mixin这样的方法来初始化一些功能,具体的我们后面在分析,不过通过代码我们可以确认的是:没错!这里确实是导出了一个 Vue 功能类。

    接下来,我们接着看initGlobalAPI这个东西,其实在Vue官网上,就已经为我们说明了Vue的全局属性:

    关于全局API

    那我们来看看,是不是这么回事(内容太多,只贴一下主要的代码):

    // core/global-api/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)
    
      // 这些工具方法不视作全局API的一部分,除非你已经意识到某些风险,否则不要去依赖他们
      Vue.util = {
        warn,
        extend,
        mergeOptions,
        defineReactive
      }
      // 这里定义全局属性
      Vue.set = set
      Vue.delete = del
      Vue.nextTick = nextTick
    
      Vue.options = Object.create(null)
      ASSET_TYPES.forEach(type => {
        Vue.options[type + 's'] = Object.create(null)
      })
      Vue.options._base = Vue
      extend(Vue.options.components, builtInComponents)
    
      // 定义全局方法
      initUse(Vue)
      initMixin(Vue)
      initExtend(Vue)
      initAssetRegisters(Vue)
    }
    
    
    • 【Vue.config】 各种全局配置项

    • 【Vue.util】 各种工具函数,还有一些兼容性的标志位(哇,不用自己判断浏览器了,Vue已经判断好了)

    • 【Vue.set/delete】 这个你文档应该见过

    • 【Vue.nextTick】

    • 【Vue.options】 这个options和我们上面用来构造实例的options不一样。这个是Vue默认提供的资源(组件指令过滤器)。

    • 【Vue.use】 通过initUse方法定义

    • 【Vue.mixin】 通过initMixin方法定义

    • 【Vue.extend】通过initExtend方法定义

    接下来便是提供给ssr使用的全局变量$isServer$ssrContext。 关于他们的使用,其实ssr文档也有说明:Head 管理

    到这里,我们的入口文件差不多就了解清楚了,接下来,我们开始去了解一下 Vue class 的具体实现,其中我们会了解到Vue的相关生命周期的知识。

    End?

    文章前后也是利用碎片时间总结整理而成,有些也是翻阅了很多的资料,也有过引用巨人的段落,文章中有所标注。如果没有标注,可能是本人忘记了,欢迎提醒。文章中如果有笔误或者不正确的解释,也欢迎批评指正,共同进步。

    最后:

    github地址

    部分源码demo

  • 相关阅读:
    【★】KMP算法完整教程
    【★】KMP算法完整教程
    算法之【牛顿迭代法】
    算法之【牛顿迭代法】
    【★】Web精彩实战之
    【★】Web精彩实战之
    ★RFC标准库_目录链接
    ★RFC标准库_目录链接
    ★教师工资为什么这么低?/整理
    ★教师工资为什么这么低?/整理
  • 原文地址:https://www.cnblogs.com/tiedaweishao/p/8933153.html
Copyright © 2011-2022 走看看