Vue原始碼學習二 ———— Vue原型物件包裝
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建構函式包裝