Vue原型對象的包裝 在Vue官網直接通過 script 標簽導入的 Vue包是 umd模塊的形式。在使用前都通過 new Vue({})。記錄一下 Vue構造函數的包裝。 在 src/core/instance/index.js 這個文件是 Vue構造函數的出生地。 javascript impo ...
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構造函數包裝