摘要:上一篇文章我們寫到從入口文件一步步找到的構(gòu)造函數(shù),現(xiàn)在我們要去看看實(shí)例化經(jīng)歷的過(guò)程的構(gòu)造函數(shù)我們知道的構(gòu)造函數(shù)在中不明白的可以去看上一篇文章源碼學(xué)習(xí)筆記一。
上一篇文章我們寫到從入口文件一步步找到Vue的構(gòu)造函數(shù),現(xiàn)在我們要去看看Vue實(shí)例化經(jīng)歷的過(guò)程Vue的構(gòu)造函數(shù)
我們知道Vue的構(gòu)造函數(shù)在src/core/instance/index.js中,不明白的可以去看上一篇文章 Vue源碼學(xué)習(xí)筆記一。那我們關(guān)注一下Vue的構(gòu)造函數(shù)的內(nèi)容:
// src/core/instance/index.js import { initMixin } from "./init" // Vue的構(gòu)造函數(shù) function Vue (options) { //... 驗(yàn)證環(huán)境 this._init(options) } // 在Vue原型上綁定實(shí)例方法 initMixin(Vue) // init stateMixin(Vue) // $set $delete $watch eventsMixin(Vue) // $on $once $off $emit lifecycleMixin(Vue) // _update $forceUpdate $destroy renderMixin(Vue) // $nextTick _render添加Vue屬性和方法
這邊我們可以看到Vue的構(gòu)造函數(shù)中執(zhí)行了init方法,從下方得知init是在srccoreinstanceinit.js中導(dǎo)出的initMixin函數(shù)中定義的
initMixinvm即this ,同時(shí)為實(shí)例添加一個(gè)唯一的uid, vm._isVue = true 監(jiān)聽(tīng)對(duì)象變化時(shí)用于過(guò)濾vm,因?yàn)閂ue的實(shí)例是不需要監(jiān)聽(tīng)變化的。
// src/core/instance/init.js Vue.prototype._init = function (options?: Object) { const vm: Component = this // 當(dāng)前實(shí)例添加了一個(gè)唯一的uid vm._uid = uid++ // ... // 監(jiān)聽(tīng)對(duì)象變化時(shí)用于過(guò)濾vm vm._isVue = true //... }
參數(shù)處理,根據(jù)我們的小栗子,我們的options處理直接進(jìn)入了else,然后對(duì)參數(shù)進(jìn)行合并,這里是對(duì)vue extend的參數(shù)需要進(jìn)行合并處理,我們這里resolveConstructorOptions 返回的即是constructor.options本身
生命周期相關(guān)變量初始化 initLifecycle(vm)
// srccoreinstancelifecycle.js // 為組件掛載相應(yīng)屬性,并初始化 vm.$parent = parent vm.$root = parent ? parent.$root : vm vm.$children = [] vm.$refs = {} vm._watcher = null vm._inactive = null vm._directInactive = false vm._isMounted = false vm._isDestroyed = false vm._isBeingDestroyed = false
4.vm 事件監(jiān)聽(tīng)初始化 initEvents()
// src/core/instance/events.js export function initEvents (vm: Component) { // 創(chuàng)建事件對(duì)象,用于存儲(chǔ)事件 vm._events = Object.create(null) // 系統(tǒng)事件標(biāo)識(shí)位 vm._hasHookEvent = false // init parent attached events npm // 將父組件模板中注冊(cè)的事件放到當(dāng)前組件實(shí)例的listeners const listeners = vm.$options._parentListeners if (listeners) { updateComponentListeners(vm, listeners) } }
initEvents(vm) initRender(vm) callHook(vm, "beforeCreate") initInjections(vm) // vm狀態(tài)初始化,prop/data/computed/method/watch都在這里初始化完成,vue實(shí)例create的關(guān)鍵 initState(vm) initProvide(vm) callHook(vm, "created")stateMixin
Vue實(shí)例方法--數(shù)據(jù),該文件對(duì)應(yīng)的是Vue的數(shù)據(jù)的處理,首先對(duì)$data進(jìn)行掛載,然后設(shè)置數(shù)據(jù)$set、刪除數(shù)據(jù)$delete、觀測(cè)數(shù)據(jù)$watch方法掛載
// stateMixin(Vue) src/core/instance/state.js export function stateMixin (Vue: ClasseventsMixin) { // data const dataDef = {} dataDef.get = function () { return this._data } // prop const propsDef = {} propsDef.get = function () { return this._props } // ... // 定義$data & prop屬性 Object.defineProperty(Vue.prototype, "$data", dataDef) Object.defineProperty(Vue.prototype, "$props", propsDef) // 原型鏈添加函數(shù)set 和 delete Vue.prototype.$set = set Vue.prototype.$delete = del // 原型鏈添加函數(shù)$watch Vue.prototype.$watch = function (){ // ... } }
Vue實(shí)例方法--事件,該文件主要掛載Vue實(shí)例方法的事件,監(jiān)聽(tīng)事件on once、移除事件off、觸發(fā)事件emit的掛載
// eventsMixin(Vue) src/core/instance/events.js export function eventsMixin (Vue: ClasslifecycleMixin) { Vue.prototype.$on = function (event: string, fn: Function): Component { // ... } Vue.prototype.$once = function (event: string, fn: Function): Component { // ... } Vue.prototype.$off = function (event?: string, fn?: Function): Component { // ... } Vue.prototype.$emit = function (event: string): Component { // ... } }
Vue實(shí)例方法--生命周期,,該文件主要掛載Vue實(shí)例方法中的生命周期方法,重新渲染$forceUpdate()、銷毀實(shí)例$destroy()
// lifecycleMixin(Vue) src/core/instance/lifecycle.js Vue.prototype._mount = function(){} Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {} Vue.prototype._updateFromParent = function(){} Vue.prototype.$forceUpdate = function () {} Vue.prototype.$destroy = function () {}renderMixin
文件主要掛載Vue實(shí)例方法中的dom更新回調(diào)$nextTick及一些其他的render函數(shù),后續(xù)我們?cè)俚纳钔谝幌?/pre>// renderMixin(Vue) src/core/instance/render.js Vue.prototype.$nextTick = function (fn: Function) {} Vue.prototype._render = function (): VNode {} Vue.prototype._s = _toString Vue.prototype._v = createTextVNode Vue.prototype._n = toNumber Vue.prototype._e = createEmptyVNode Vue.prototype._q = looseEqual Vue.prototype._i = looseIndexOf Vue.prototype._m = function(){} Vue.prototype._o = function(){} Vue.prototype._f = function resolveFilter (id) {} Vue.prototype._l = function(){} Vue.prototype._t = function(){} Vue.prototype._b = function(){} Vue.prototype._k = function(){}全局API上面部分,我們對(duì)Vue的構(gòu)造函數(shù),在src/core/instance/index.js文件中的作用進(jìn)行了大體的了解,當(dāng)然這并沒(méi)有結(jié)束,依據(jù)我們Vue源碼學(xué)習(xí)筆記一中提到的,我們追溯到上一級(jí)src/core/index.js// src/core/index.js import Vue from "./instance/index" import { initGlobalAPI } from "./global-api/index" import { isServerRendering } from "core/util/env" import { FunctionalRenderContext } from "core/vdom/create-functional-component" // 初始化全局變量 initGlobalAPI(Vue) // 為vue原型定義屬性 isServer 判斷是否為服務(wù)端渲染 Object.defineProperty(Vue.prototype, "$isServer", { get: isServerRendering }) // 為vue原型定義屬性 ssrContext Object.defineProperty(Vue.prototype, "$ssrContext", { get () { /* istanbul ignore next */ return this.$vnode && this.$vnode.ssrContext } }) Object.defineProperty(Vue, "FunctionalRenderContext", { value: FunctionalRenderContext }) Vue.version = "__VERSION__" export default VueinitGlobalAPI(Vue)在Vue 構(gòu)造函數(shù)上掛載靜態(tài)屬性和方法即全局API// src/core/global-api/index.js export function initGlobalAPI(Vue: GlobalAPI) { const configDef = {} configDef.get = () => config // ... Object.defineProperty(Vue, "config", configDef) Vue.util = { // Vue.util warn, extend, mergeOptions, defineReactive } Vue.set = set Vue.delete = del Vue.nextTick = nextTick Vue.options = Object.create(null) ASSET_TYPES.forEach(type => { Vue.options[type + "s"] = Object.create(null) }) Vue.options._base = Vue extend(Vue.options.components, builtInComponents) initUse(Vue) // Vue.use initMixin(Vue) // Vue.mixin initExtend(Vue) // Vue.extend initAssetRegisters(Vue) // Vue.component Vue.directive Vue.filter }內(nèi)置組件&命令在追溯到上一級(jí),在文件src/platforms/web/runtime/index.js,該文件注冊(cè)了一些 Vue內(nèi)置的組件:包裹動(dòng)態(tài)組件KeepAlive、元素過(guò)渡效果Transition、多個(gè)元素過(guò)渡TransitionGroup// src/platforms/web/runtime/index.js 執(zhí)行后 // 安裝平臺(tái)特定的utils Vue.config.isUnknownElement = isUnknownElement Vue.config.isReservedTag = isReservedTag Vue.config.getTagNamespace = getTagNamespace Vue.config.mustUseProp = mustUseProp // 安裝平臺(tái)特定的 指令 和 組件 Vue.options = { components: { KeepAlive, Transition, TransitionGroup }, directives: { model, show }, filters: {}, _base: Vue } Vue.prototype.__patch__ Vue.prototype.$mountcompiler編譯器添加再上一級(jí)為src/platforms/web/entry-runtime-with-compiler.js,該文件對(duì)原來(lái)的Vue.prototype.$mount進(jìn)行覆蓋定義,并且在Vue上掛載了 compile。給Vue的 $mount 方法添加 compiler 編譯器,支持 template。// src/platforms/web/entry-runtime-with-compiler.js const mount = Vue.prototype.$mount // ... Vue.prototype.$mount = function (){ //... 覆蓋 Vue.prototype.$mount } // ... //在 Vue 上掛載 compile //compileToFunctions 函數(shù)的作用,就是將模板 template 編譯為render函數(shù)。 Vue.compile = compileToFunctions總結(jié)至此的話我們從宏觀上過(guò)了一下從我們一層層找到vue到一層層往外看到對(duì)Vue的添加屬性方法等,我們有了一個(gè)整體的概念
src/core/instance/index.js vue的構(gòu)造函數(shù),添加Vue屬性和方法
src/core/index.js 全局API的掛載
src/platforms/web/runtime/index.js 主要是添加web平臺(tái)特有的配置、組件和指令
web/entry-runtime-with-compiler.js 給Vue的 $mount 方法添加 compiler 編譯器,支持 template
scripts/config.js 編譯入口文件
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99898.html
摘要:其中執(zhí)行命令是我們當(dāng)前所關(guān)注的,對(duì)于項(xiàng)目的文件結(jié)構(gòu),我們需要去找到項(xiàng)目的啟動(dòng)的入口文件,接下來(lái)我們?nèi)ヒ徊揭徊降恼业椒治雒钍且粋€(gè)模塊打包器。 打算開(kāi)始學(xué)習(xí)vue的源碼開(kāi)始,我開(kāi)始 serach 關(guān)鍵詞:vue 源碼,可是發(fā)現(xiàn)很多都不是我想要看到的東西,所以打算記錄下來(lái),學(xué)習(xí)的記錄和日后分享。我在想這個(gè)文章的名字時(shí),手把手系列?十分鐘系列?小白到大佬系列?都不是,只是單純的學(xué)習(xí)筆記 文件...
摘要:一個(gè)基于全家桶開(kāi)發(fā)的仿知乎日?qǐng)?bào)單頁(yè)應(yīng)用項(xiàng)目地址源碼地址項(xiàng)目在線地址在線地址模式下推薦使用移動(dòng)端模式瀏覽去觀看如果覺(jué)得做得還不錯(cuò)或者項(xiàng)目源碼對(duì)您有幫助希望您小抬右手到右上角點(diǎn)一個(gè)您的支持是作者長(zhǎng)期更新維護(hù)的動(dòng)力項(xiàng)目起源從二月份開(kāi)始學(xué)習(xí)學(xué)習(xí)了 Vue-News 一個(gè)基于vue全家桶開(kāi)發(fā)的仿知乎日?qǐng)?bào)單頁(yè)應(yīng)用 項(xiàng)目github地址:源碼地址 項(xiàng)目在線地址:在線地址 (PC模式下推薦使用chro...
摘要:很多小伙伴練手都會(huì)去仿寫豆瓣電影或者網(wǎng)易云音樂(lè),所以,這回干脆把兩個(gè)集合起來(lái),具體長(zhǎng)什么樣,請(qǐng)各位看預(yù)覽或下面圖片啦。怎么折騰法呢比如豆瓣部分我使用了,網(wǎng)易云部分則沒(méi)有,網(wǎng)易的組件則是自己造的輪子,當(dāng)然在實(shí)際開(kāi)發(fā)中肯定不會(huì)這么搞啦。。 很多小伙伴練手都會(huì)去仿寫豆瓣電影或者網(wǎng)易云音樂(lè),所以,這回干脆把兩個(gè)集合起來(lái),具體長(zhǎng)什么樣,請(qǐng)各位看預(yù)覽或下面圖片啦。 目的: 做這個(gè)項(xiàng)目最主要的目的是...
摘要:介一回聊狀態(tài)模式,官方描述允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。有限狀態(tài)機(jī)有限狀態(tài)機(jī)是一個(gè)非常有用的模型,可以模擬世界上大部分事物。這個(gè)是官方說(shuō)法,簡(jiǎn)單說(shuō),她有三個(gè)特征,狀態(tài)總數(shù)是有限的。,任一時(shí)刻,只處在一種狀態(tài)之中。 本回內(nèi)容介紹 上一回聊了聊組合模式(Composite),用組合模式模擬了個(gè)圖片庫(kù),聊了遞歸。介一回聊狀態(tài)模式(State),官方描述允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改...
寫文章不容易,點(diǎn)個(gè)贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】Compile - 源碼版 之 Parse 主要流程 本文難度較繁瑣,需要耐心觀看,如果你對(duì) compile 源碼暫時(shí)...
閱讀 1360·2023-04-25 23:42
閱讀 2855·2021-11-19 09:40
閱讀 3534·2021-10-19 11:44
閱讀 3573·2021-10-14 09:42
閱讀 1876·2021-10-13 09:39
閱讀 3843·2021-09-22 15:43
閱讀 679·2019-08-30 15:54
閱讀 1461·2019-08-26 13:32