Vue原型对象的包装
在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式。在使用前都通过 new Vue({})。记录一下 Vue构造函数的包装。
在 src/core/instance/index.js 这个文件是 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) {
// 使用安全模式来提醒要使用new操作符来调用Vue
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)
}
/**
* 在执行npm run dev构建运行时执行, 包装Vue.prototype。为其添加一些属性和方法
*/
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
首先导入了五个方法
- initMixin
- stateMixin
- renderMixin
- eventsMixin
- lifecycleMixin
如果不是在生产环境下,且不通过 new 来调用Vue 会得到警告。
接下来执行 initMixin方法, 到 initMixin来源文件看。
export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (){}
}
首先会在 Vue这个构造函数的原型对象上定义一个 _init方法。这个方法是在通过 new Vue({})的时候执行。在 Vue 构造函数中可以看到 this._init(options)。
接着将 Vue构造函数作为参数传递给下一个 stateMixin方法, 到stateMixin来源文件看。
export function stateMixin (Vue: Class<Component>) {
// flow somehow has problems with directly declared definition object
// when using Object.defineProperty, so we have to procedurally build up
// the object here.
const dataDef = {}
dataDef.get = function () { return this._data }
const propsDef = {}
propsDef.get = function () { return this._props }
// 设置两个只读的属性 $data $props
if (process.env.NODE_ENV !== 'production') {
dataDef.set = function () {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
}
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
Vue.prototype.$set = set
Vue.prototype.$delete = del
Vue.prototype.$watch = function (){}
}
其中Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
这是在 Vue的原型对象上定义了两个属性 $data
和 $props
。其中分别代理了 _data
和 _props
。看 dataDef 这个对象上定义了一个 get 方法, 最终返回当前实例对象的 _data。props 也是这样子的。
if (process.env.NODE_ENV !== 'production') {
dataDef.set = function () {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
}
当你在非生产环境时, 如果修改 $data 和 $props会得到警告信息。
最后在 Vue.prototype上还定义了 $set、$delete以及 $watch。。
接下来是 eventMixin方法, 进入这个方法的来源文件
export function eventsMixin (Vue: Class<Component>) {
Vue.prototype.$on = function(){};
Vue.prototype.$once = function(){};
Vue.prototype.$off = function(){};
}
又再 Vue.prototype 上定义了三个方法, 分别是 $on
、$once
和$off
。
接下来执行 lifecycleMixin 方法, 看lifecycleMixin方法的来源文件:
export function lifecycleMixin (Vue: Class<Component>) {
Vue.prototype._update = function() {}
Vue.prototype.$forceUpdate = function() {}
Vue.prototype.$destroy = function(){}
在 lifecycleMixin 方法中又向 Vue的原型对象 prototype上添加了三个方法。分别是 _update
、$$forceUpdate
和$$destroy
。
$forceUpdate: 迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
最后一个执行 renderMixin方法。在renderMixin来源文件可以到。
首先执行了一个 installRenderHelpers(Vue.prototype),这个方法的主要作用也是向 Vue.prototype上添加方法, 看它源文件是:
// 这个函数主要在Vue.prototype上面添加一些方法
export function installRenderHelpers (target: any) {
target._o = markOnce
target._n = toNumber
target._s = toString
target._l = renderList
target._t = renderSlot
target._q = looseEqual
target._i = looseIndexOf
target._m = renderStatic
target._f = resolveFilter
target._k = checkKeyCodes
target._b = bindObjectProps
target._v = createTextVNode
target._e = createEmptyVNode
target._u = resolveScopedSlots
target._g = bindObjectListeners
}
紧接着又向 Vue.prototype对象上添加了 $nextTick和_render方法。
export function renderMixin (Vue: Class<Component>) {
// install runtime convenience helpers
installRenderHelpers(Vue.prototype)
Vue.prototype.$nextTick = function (fn: Function) {
return nextTick(fn, this)
}
Vue.prototype._render = function (): VNode {}
执行完 renderMixin这个方法, Vue构造函数的出生文件也运行完了。也就是指在 npm run dev命令构建时运行。这里的每一个方法 *Mixin的作用就是包装 Vue.prototype, 对其挂载一些属性和方法。最后 export default Vue
将其导出这个构造函数。此时 Vue.prototype上添加的属性和方法有这些。
然后在哪里用到了呢。在 src/core/index.js中导入了Vue的出生文件。看Vue源码学习三 ———— Vue构造函数包装
Vue源码学习二 ———— Vue原型对象包装的更多相关文章
-
Vue源码学习1——Vue构造函数
Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...
-
Vue源码学习三 ———— Vue构造函数包装
Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...
-
Vue源码分析(二) : Vue实例挂载
Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...
-
vue 源码学习二 实例初始化和挂载过程
vue 入口 从vue的构建过程可以知道,web环境下,入口文件在 src/platforms/web/entry-runtime-with-compiler.js(以Runtime + Compil ...
-
vue 源码学习三 vue中如何生成虚拟DOM
vm._render 生成虚拟dom 我们知道在挂载过程中, $mount 会调用 vm._update和vm._render 方法,vm._updata是负责把VNode渲染成真正的DOM,vm._ ...
-
Vue源码学习一 ———— Vue项目目录
Vue 目录结构 可以在 github 上通过这款 Chrome 插件 octotree 查看Vue的文件目录.也可以克隆到本地.. Vue 是如何规划目录的 scripts ------------ ...
-
Vue源码学习(二)$mount() 后的做的事(1)
Vue实例初始化完成后,启动加载($mount)模块数据. (一)Vue$3.protype.$mount 标红的函数 compileToFunctions 过于复杂,主要是生 ...
-
手牵手,从零学习Vue源码 系列二(变化侦测篇)
系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 陆续更新中... 预计八月中旬更新完毕. 1 概述 Vue最大的特点之一就是数据驱动视 ...
-
【Vue源码学习】依赖收集
前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...
随机推荐
-
[Hadoop in Action] 第5章 高阶MapReduce
链接多个MapReduce作业 执行多个数据集的联结 生成Bloom filter 1.链接MapReduce作业 [顺序链接MapReduce作业] mapreduce-1 | mapr ...
-
ocket.chat 使用 Meteor 开发的实时协作工具,类似 丁丁。
ocket.chat 使用 Meteor 开发的实时协作工具,类似 丁丁. https://rocket.chat/
-
【转】SDP file
SDP file Introduction The Session Description Protocol (SDP) is a format for describing the initiali ...
-
[Bhatia.Matrix Analysis.Solutions to Exercises and Problems]ExI.2.5
Show that matrices with distinct eigenvalues are dense in the space of all $n\times n$ matrices. (Us ...
-
Jquery 对象集合的迭代扩展forEach
if (jQuery && !jQuery.fn.forEach) { $(function () { (function ($) { $.fn.extend({ forEach: f ...
-
查看android进程信息
打开adb shell.直接ps命令 假设查看某特定进程,比方<圣火英雄传>.用grep过滤 各列參数意义: USER 进程当前用户: PID Pro ...
-
poj 1080
http://poj.org/problem?id=1080 知识点 :最长公共子序列 要点: 转移方程 f[i][j] = max{ f[i-i][j]+score[s1[i-1]]['-'], ...
-
laravel中with()方法,has()方法和whereHas()方法的区别
with() with()方法是用作"渴求式加载"的,那主要意味着,laravel将会伴随着主要模型预加载出确切的的关联关系.这就对那些如果你想加在一个模型的所有关联关系非常有帮助 ...
-
[C#]如何访问及调用类中私有成员及方法
本文为原创文章.源代码为原创代码,如转载/复制,请在网页/代码处明显位置标明原文名称.作者及网址,谢谢! 开发工具:VS2017 语言:C# DotNet版本:.Net FrameWork 4.0及以 ...
-
Python爬虫4-URLError与HTTPError
GitHub代码练习地址:URLError:https://github.com/Neo-ML/PythonPractice/blob/master/SpiderPrac06_URLError.py ...