初步讀完vue(v2.6.10)
的源碼,現將讀後感記錄以下,故事就是由此開始。vue
小提示:配合源碼食用更佳美味。node
開始的開始,vue就是一個簡單的函數。web
src/core/instance/index.js設計模式
function Vue (options) {
this._init(options)
}
複製代碼
設計模式之混入模式,對Vue進行擴展,很值得學習的一種方式。api
定義了_init方法,是入口函數,在new Vue()時第一時間執行的方法。緩存
src/core/instance/init.jsbash
Vue.prototype._init = function (options?: Object){}
複製代碼
數據相關的擴展。dom
src/core/instance/state.js函數
Vue
實例觀察的數據對象和當前組件接收到的props
對象。 其實是代理到_data
和_props
工具
Object.defineProperty(Vue.prototype, '$data', {
get(){
return this._data
}
})
Object.defineProperty(Vue.prototype, '$props', {
get(){
return this._props
}
})
複製代碼
是 Vue.set
和Vue.delete
的別名
Vue.prototype.$set = set
Vue.prototype.$delete = del
複製代碼
實現了$watch
方法,觀察Vue
實例變化的一個表達式或計算屬性函數。
Vue.prototype.$watch = function () {}
複製代碼
事件相關的擴展
src/core/instance/events.js
監聽當前實例上的自定義事件。
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component{}
複製代碼
監聽一個自定義事件,可是隻觸發一次。一旦觸發以後,監聽器就會被移除。
Vue.prototype.$once = function (event: string, fn: Function): Component{}
複製代碼
移除自定義事件監聽器。
Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function): Component{}
複製代碼
觸發當前實例上的事件。
Vue.prototype.$emit = function (event: string): Component {}
複製代碼
生命週期相關的擴展
src/core/instance/lifecycle.js
私有方法,更新dom節點流程的重要函數
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
複製代碼
迫使 Vue 實例從新渲染。簡單粗暴
Vue.prototype.$forceUpdate = function (){ // 觸發更新}
複製代碼
徹底銷燬一個實例。
Vue.prototype.$destroy = function (){ // 移除事件 指令等 }
複製代碼
render相關的擴展
src/core/instance/render.js
定義render函數有關的方法,在執行render時使用
src/core/instance/render-helpers/index.js
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
target._d = bindDynamicKeys
target._p = prependModifier
}
複製代碼
將回調延遲到下次 DOM 更新循環以後執行。跟Vue.nextTick
同樣,可是綁定了實例的this
Vue.prototype.$nextTick = function (fn: Function) {
return nextTick(fn, this)
}
複製代碼
私有方法,建立vnode流程的重要函數
Vue.prototype._render = function (): VNode{}
複製代碼
src/core/index.js
全局api
src/core/global-api/index.js
vue 全局配置 代理到vue的config,在new Vue()以前能夠修改
全局配置 src/core/config.js
import config from '../config'
Object.defineProperty(Vue, 'config', {
get() {
return config
}
})
複製代碼
vue的工具函數
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
複製代碼
Vue.set = set // 向響應式對象中添加一個屬性
Vue.delete = del // 刪除對象的屬性。
Vue.nextTick = nextTick // 在下次 DOM 更新循環結束以後執行延遲迴調。
複製代碼
讓一個對象可響應。
Vue.observable = <T>(obj: T): T => {
observe(obj)
return obj
}
複製代碼
默認的options
Vue.options = Object.create(null)
複製代碼
組件、指令、過濾器實際上就是在options中建立了三個屬性。
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
// Vue.options.components
// Vue.options.directives
// Vue.options.filters
複製代碼
私有屬性,緩存Vue
Vue.options._base = Vue
複製代碼
定義了內部組件KeepAlive
extend(Vue.options.components, builtInComponents)
複製代碼
定義了Vue.use方法, 安裝 Vue.js 插件。
src/core/global-api/use.js
Vue.use = function (plugin: Function | Object) {}
複製代碼
定義了Vue.mixin方法, 全局註冊一個混入
src/core/global-api/mixin.js
Vue.mixin = function (mixin: Object) {}
複製代碼
定義了Vue.extend方法, Vue 構造器,建立一個「子類」。
src/core/global-api/extend.js
Vue.extend = function (extendOptions: Object): Function
複製代碼
用於實現組件、指令、過濾器方法
Vue.directive 註冊或獲取全局指令。
Vue.filter 註冊或獲取全局過濾器。
Vue.component 註冊或獲取全局組件。
src/core/global-api/assets.js
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
複製代碼
版本號
Vue.version = '__VERSION__'
複製代碼
再次之上是vue的核心代碼,與平臺無關。如下是web平臺有關代碼。 咱們一般用cli
寫的代碼是不須要編譯器的,由於vue-loader有一個編譯過程,這個版本一般較小,可是不帶編譯器。
僅運行時的版本
src/platforms/web/entry-runtime.js
實際上就是src/platforms/web/runtime/index.js
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement
複製代碼
平臺相關 定義內部指令v-model
和v-show
extend(Vue.options.directives, platformDirectives)
複製代碼
平臺相關 定義內部組件Transition
和TransitionGroup
,上面提到過平臺無關的內部組件KeepAlive
extend(Vue.options.components, platformComponents)
複製代碼
打補丁方法,平臺不同打補丁的方法也不同,設計很巧妙。
Vue.prototype.__patch__ = inBrowser ? patch : noop
複製代碼
若是 Vue 實例在實例化時沒有收到 el 選項,則它處於「未掛載」狀態,沒有關聯的 DOM 元素。可使用 vm.$mount()
手動地掛載一個未掛載的實例。
最後執行了實際上是src/core/instance/lifecycle.js
中的mountComponent
方法。也就是對mountComponent
的一次封裝
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
複製代碼
這個版本比較大,由於帶有編譯器。
src/platforms/web/entry-runtime-with-compiler.js
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
const options = this.$options
// 其實所謂的編譯就是講模板編譯成render函數
// 存在render將直接使用render函數,則不須要編譯
// 不存在render則讀取template template有害幾種配置方法也是在此到處理
if (template) {
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
}
// 實際仍是調用了$mount
return mount.call(this, el, hydrating)
}
複製代碼
在 render 函數中編譯模板字符串 編譯器版本特有。
Vue.compile = compileToFunctions
複製代碼
感謝各位的閱讀,錯誤是在所不免的,如有錯誤,或者有更好的理解,請在評論區留言,再次感謝。但願你們相互學習,共同進步。