Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数
来到 src/core/index.js
代码是:
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/shared/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
// 将 Vue 构造函数作为参数, 传递给 initGlobalAPI 方法
// 向Vue.prototype 上添加一些静态属性和方法
initGlobalAPI(Vue)
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
})
Vue.version = '__VERSION__'
// http://hcysun.me/vue-design/art/2vue-constructor.html#with-compiler
export default Vue
看第一句 import Vue from './instance/index'
, 导入了Vue这个构造函数,且原型在上面已经添加了一些属性和方法。
然后 initGlobalAPI(Vue)
执行 initGlobalAPI 方法并且将 Vue构造函数就为参数调用。
又再 Vue的原型上添加了两个只读的属性 $isServer、$ssrContext
。并且再 Vue构造函数上定义了 FunctionalRenderContext
静态属性,之所以在 Vue构造函数上定义,是因为在 ssr的时候要使用它。最后 Vue.version = '__VERSION__'
又在 Vue构造函数上定义了version,即版本号。
然后再看 initGlobalAPI
方法的来源地, 它主要是丰富 Vue构造函数,在构造函数上添加静态属性和方法。import { initGlobalAPI } from './global-api/index'。 来到 ./global-api/index.js
文件中
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.'
)
}
}
// Vue构造函数上添加config属性, 也是只读的属性。
// Vue.config 代理的是从../config文件导出的对象
Object.defineProperty(Vue, 'config', configDef)
首先是这样的一段代码, 这段代码是在 Vue构造函数上添加 config
属性, 他也是一个只读的属性,和 $data
、$prop
是一样的。当你试图修改这个属性时,在非生产环境下会给你提醒warn
。
这个 config从哪里来的呢, 这个文件的最顶部 import config from '../config'
。
所以 Vue.config 代理的是从 core/config
导入的config对象。
然后是这样一段代码:
// exposed shared 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原型上添加了一个 util属性,它是一个对象。这个对象有四个属性 warn、extend、mergeOptions、defineReactive
。他们都是来自于 src/core/util/index
文件中。官网上没有这些api的说明, 也不推荐使用。
然后是一段这样的代码:
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
// options 通过Object.create()创建的一个空对象
Vue.options = Object.create(null)
上面这段代码是在 Vue构造函数上又添加了四个属性 set、delete、nextTick
和 options
。options
是通过 Object.create(null)
创建的一个空对象。下面的代码即丰富了 options
这个对象。
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
ASSET_TYPES
是上面呢?很明显他是一个数组,遍历它的每一个属性 + s 并且添加到 Vue.options上。并且初始赋值的都是 Object.create(null)
。看一下 ASSET_TYPES
来自src/shared/constants.js
文件。
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
可以看到 ASSET_TYPES
是这么一个数组。原来是通过遍历向 Vue.options中添加 components、directives、filters
。
到目前,Vue.options现在是这样样子:
Vue.options = {
components: Object.create(null),
directives: Object.create(null),
filters: Object.create(null),
_base: Vue
}
然后继续向下看是这样的一句代码
extend(Vue.options.components, builtInComponents)
extend
是 Vue的一个工具方法,在 src/shared/util.js
文件中
/**
* Mix properties into target object.
*/
export function extend (to: Object, _from: ?Object): Object {
for (const key in _from) {
to[key] = _from[key]
}
return to
}
主要作用是将一个对象的属性混入到另外一个对象中。
那么上面的 extend(Vue.options.components, builtInComponents)
的意思就是将 builtInComponents
对象的属性混入到 Vue.options.components
对象中。那么builtInComponents
对象是啥呢? 来到 src/core/components/indes.js
文件中:
import KeepAlive from './keep-alive'
export default {
KeepAlive
}
就是将 KeepAlive
这个属性添加到 Vue.options.conponents
中。
那么到目前为止, Vue.options对象已经变成了这个样子
Vue.options = {
components: {
KeepAlive
},
directives: Object.create(null),
filters: Object.create(null),
_base: Vue
}
再看这个文件的最后一部分代码
initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)
依此调用了四个方法,都是将 Vue这个构造函数作为其参数。initUse、initMixin、initExtend、initAssetRegisters
四个方法分别来自 ./global-api/use.js
、./global-api/mixin.js
、./global-api/extend.js
、./global-api/assets.js
文件。
先看 initUse
文件:
// 全局的 Vue.use() 用来安装插件的方法
export function initUse (Vue: GlobalAPI) {
Vue.use = function(){}
}
该方法的主要作用是在 Vue上添加 use方法,也就是用来安装 Vue插件的全局API Vue.use()
。
initMixin
文件
// 在Vue上添加mixin的全局API
export function initMixin (Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin)
return this
}
}
initMixin
方法的主要作用是在 Vue原型上添加 mixin
这个全局API。再看 initExtend
initExtend
文件
export function initExtend (Vue: GlobalAPI) {
/**
* Each instance constructor, including Vue, has a unique
* cid. This enables us to create wrapped "child
* constructors" for prototypal inheritance and cache them.
*/
Vue.cid = 0
let cid = 1
/**
* Class inheritance
*/
// 使用基础Vue构造器, 创建一个"子类", 参数是一个包含组件选项的对象
// API 详细 https://cn.vuejs.org/v2/api/#Vue-extend
// ...
Vue.extend = function (extendOptions: Object): Function {
}
}
这个方法在 Vue构造函数上添加了 cid、extend
一个静态属性和一个静态方法。
最后一个 initAssetRegisters
文件
import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from '../util/index'
export function initAssetRegisters (Vue: GlobalAPI) {
/**
* Create asset registration methods.
*/
ASSET_TYPES.forEach(type => {
Vue[type] = function (){}
}
ASSET_TYPES
这个文件前面见到过:
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
这个方法的主要作用是在 Vue 构造函数上添加全局的 component、directive、filter
, 分别用来注册 全局组件、指令、过滤器
的。
initGlobalAPI
这个方法就说完了。就是在 Vue这个构造函数上定义静态属性和方法。Vue的出生文件是在 Vue原型对象上丰富了内容,现在又再 Vue构造函数上丰富了内容。
到现在 Vue 构造函数上有以下属性和方法
// initGlobalAPI
Vue.config
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
Vue.options = {
components: {
KeepAlive
},
directives: Object.create(null),
filters: Object.create(null),
_base: Vue
}
// initUse ***************** global-api/use.js
Vue.use = function (plugin: Function | Object) {}
// initMixin ***************** global-api/mixin.js
Vue.mixin = function (mixin: Object) {}
// initExtend ***************** global-api/extend.js
Vue.cid = 0
Vue.extend = function (extendOptions: Object): Function {}
// initAssetRegisters ***************** global-api/assets.js
Vue.component =
Vue.directive =
Vue.filter = function (
id: string,
definition: Function | Object
): Function | Object | void {}
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
})
Vue.version = '__VERSION__'
Vue源码学习三 ———— Vue构造函数包装的更多相关文章
-
vue 源码学习三 vue中如何生成虚拟DOM
vm._render 生成虚拟dom 我们知道在挂载过程中, $mount 会调用 vm._update和vm._render 方法,vm._updata是负责把VNode渲染成真正的DOM,vm._ ...
-
Vue源码学习二 ———— Vue原型对象包装
Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...
-
Vue源码学习1——Vue构造函数
Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...
-
Vue源码学习一 ———— Vue项目目录
Vue 目录结构 可以在 github 上通过这款 Chrome 插件 octotree 查看Vue的文件目录.也可以克隆到本地.. Vue 是如何规划目录的 scripts ------------ ...
-
【Vue源码学习】依赖收集
前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...
-
Vue源码学习(一):调试环境搭建
最近开始学习Vue源码,第一步就是要把调试环境搭好,这个过程遇到小坑着实费了点功夫,在这里记下来 一.调试环境搭建过程 1.安装node.js,具体不展开 2.下载vue项目源码,git或svn等均可 ...
-
最新 Vue 源码学习笔记
最新 Vue 源码学习笔记 v2.x.x & v3.x.x 框架架构 核心算法 设计模式 编码风格 项目结构 为什么出现 解决了什么问题 有哪些应用场景 v2.x.x & v3.x.x ...
-
Vue源码分析(二) : Vue实例挂载
Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...
-
Vue2.x源码学习笔记-Vue构造函数
我们知道使用vue.js开发应用时,都是new Vue({}/*options*/) 那Vue构造函数上有哪些静态属性和方法呢?其原型上又有哪些方法呢? 一般我都会在浏览器中输入Vue来look se ...
随机推荐
-
1.0 多控制器管理(附:Demo)
本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书” 控制器 : 一个iOS的app很少只由一个控制器组成,除非这个app极其简 ...
-
【jQuery 冻结任意行列】冻结任意行和列的jQuery插件
实现原理: 创建多个div,div之间通过css实现层叠,每个div放置当前表格的克隆.例如:需要行冻结时,创建存放冻结行表格的div,通过设置z-index属性和position属性,让冻结行表格在 ...
-
CM: 使用gerrit,提交代码到CM
1. Make sure your local git username matches with your Gerrit username, Gerrit username needs to be ...
-
Get the image file(s) some informations,Including the Make,Model,Date/Time,etc
This is a blog about how to get the image file(s) some informations.Including the Make,Model,Date/Ti ...
-
【C语言】14-返回指针的函数与指向函数的指针
前言 前面我们花了接近3个章节学习指针,应该都感受到指针的强大了吧.指针可以根据地址直接操作内存中的数据,使用得当的话,不仅能使代码量变少,还能优化内存管理.提升程序性能.关于指针的内容还非常多,比如 ...
-
econ
1) If Ep > 1, Demand is elastic. 2) If Ep < 1, Demand is inelastic 3) If Ep = 1, Demand has un ...
-
Java:标示符 基本数据类型
标示符: 在程序中自定义的一些名称,例如:变量.类名.方法名…… 组成有数字0~9.大小写英文字母.“$”和下划线“_”组成,且不能由数字开头,以及不能使用java已使用和保留的关键字. Java中的 ...
-
Socket异步通信学习三
接下来是客户端部分,采用同步接收模式,在SocketClient项目中新建了一个SynServer类,用于存放socket服务器代码,和AsynServer类似,主要有4个方法: 有一个全局socke ...
-
An Easy Problem?! - POJ 2826(求面积)
题目大意:有两块木板交叉起来接雨水,问最多能接多少. 分析:题目描述很简单,不过有些细节还是需要注意到,如下图几种情况: #include<stdio.h> #include< ...
-
iOS开发——NSArray中的字典排序
手头上碰到一个项目,需要给数组中的字典中的一个字段排序,想了想,干脆再字典中增加一个字段,用来记录需要排序字段的第一个字符,用它来作为比较的对象,进行排序. - (void)viewDidLoad { ...