浅析Vue源码(一)—— 造物创世

栏目: 编程语言 · 发布时间: 6年前

内容简介:声明:英文注解为尤雨溪大神原著,中文为本人理解翻译。水平有限若理解有误请以原著为准,望指正,见谅哈~要是觉得还不错,快给我个star,快点这里Vue 项目的起源,其实是源于对Vue进行实例化:

声明:英文注解为尤雨溪大神原著,中文为本人理解翻译。水平有限若理解有误请以原著为准,望指正,见谅哈~

要是觉得还不错,快给我个star,快点这里 github

Vue 项目的起源,其实是源于对Vue进行实例化:

new Vue({
  el: ...,
  data: ...,
  ....
})
复制代码

那么在这次实例化的过程中,究竟发生了哪些行为?让我们来一探究竟。打开Vue的源码文件,其核心代码在src/core目录下。下面我们从入口文件index.js开始进入:

// 这个应该是实例化的引入
import Vue from './instance/index'
//这个应该是初始化一些全局API
import { initGlobalAPI } from './global-api/index'
// 这个应该是从判断执行环境中的引入是否是ssr环境,是一个Boolea类型
import { isServerRendering } from 'core/util/env'
// 这个应该是virtualDom编译成renderContext的方法
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
//这里开始执行初始化全局变量
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原型定义当为ssr环境运行时去加载FunctionalRenderContext方法
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
  value: FunctionalRenderContext
})

Vue.version = '__VERSION__'
// 导出Vue
export default Vue
复制代码

接下来我们来看一下各个加载文件:

import Vue from './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 功能类。

import { initGlobalAPI } from './global-api/index'
复制代码

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

浅析Vue源码(一)—— 造物创世
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 {
  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)
  // 这些 工具 方法不视作全局API的一部分,除非你已经意识到某些风险,否则不要去依赖他们
  // 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

  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.config】 各种全局配置项

♦【Vue.util】 各种工具函数,还有一些兼容性的标志位(哇,不用自己判断浏览器了,Vue已经判断好了) ♦【Vue.set/delete】 这个你文档应该见过

♦【Vue.nextTick】 这个是下一次更新前合并处理data变化做的一次优化

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

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

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

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

import { isServerRendering } from 'core/util/env'
复制代码
// 这个需要用懒加载在vue渲染前
// this needs to be lazy-evaled because vue may be required before
// ssr使用的时候要把VUE_ENV(vue环境)设置成'server'
// vue-server-renderer can set VUE_ENV
let _isServer
export const isServerRendering = () => {
  if (_isServer === undefined) {
    /* istanbul ignore if */
    if (!inBrowser && !inWeex && typeof global !== 'undefined') {
      // detect presence of vue-server-renderer and avoid
      // Webpack shimming the process
      _isServer = global['process'].env.VUE_ENV === 'server'
    } else {
      _isServer = false
    }
  }
  return _isServer
}
复制代码
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
复制代码
export function FunctionalRenderContext (
  data: VNodeData,
  props: Object,
  children: ?Array<VNode>,
  parent: Component,
  Ctor: Class<Component>
) {
  const options = Ctor.options
  // 确保createElement方法在components方法中
  // ensure the createElement function in functional components
  // 得到一个唯一的context上下文-主要是为了检查是否有重复命名确保唯一性
  // gets a unique context - this is necessary for correct named slot check
  let contextVm
  if (hasOwn(parent, '_uid')) {
  // 表示不存在创建
    contextVm = Object.create(parent)
    // $flow-disable-line
    contextVm._original = parent
  } else {
    // the context vm passed in is a functional context as well.
    // in this case we want to make sure we are able to get a hold to the
    // real context instance.
    contextVm = parent
    // $flow-disable-line
    parent = parent._original
  }
  const isCompiled = isTrue(options._compiled)
  const needNormalization = !isCompiled

  this.data = data
  this.props = props
  this.children = children
  this.parent = parent
  this.listeners = data.on || emptyObject
  this.injections = resolveInject(options.inject, parent)
  this.slots = () => resolveSlots(children, parent)
  // 支持把template编译的方法
  // support for compiled functional template
  if (isCompiled) {
    // exposing $options for renderStatic()
    this.$options = options
    // pre-resolve slots for renderSlot()
    this.$slots = this.slots()
    this.$scopedSlots = data.scopedSlots || emptyObject
  }

  if (options._scopeId) {
    this._c = (a, b, c, d) => {
      const vnode = createElement(contextVm, a, b, c, d, needNormalization)
      if (vnode && !Array.isArray(vnode)) {
        vnode.fnScopeId = options._scopeId
        vnode.fnContext = parent
      }
      return vnode
    }
  } else {
    this._c = (a, b, c, d) => createElement(contextVm, a, b, c, d, needNormalization)
  }
}

installRenderHelpers(FunctionalRenderContext.prototype)
复制代码

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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

重构

重构

Martin Fowler / 熊节 / 人民邮电出版社 / 2010 / 69.00元

重构,一言以蔽之,就是在不改变外部行为的前提下,有条不紊地改善代码。多年前,正是本书原版的出版,使重构终于从编程高手们的小圈子走出,成为众多普通程序员日常开发工作中不可或缺的一部分。本书也因此成为与《设计模式》齐名的经典著作,被译为中、德、俄、日等众多语言,在世界范围内畅销不衰。 本书凝聚了软件开发社区专家多年摸索而获得的宝贵经验,拥有不因时光流逝而磨灭的价值。今天,无论是重构本身,业界对重......一起来看看 《重构》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具