摘要:主要大綱從方法看全局配置尋根問祖的構造函數的出生地先來一段最常見的代碼上面已經創建了一個應用程序從上面很容易就看出來是一個構造器,是用這個構造器構造出來的實例化對象,實例化的時候傳入了參數,參數中包括和上述延伸了個問題構造器是什么模樣可以
主要大綱:
從initGlobalAPI方法看Vue.config全局配置
尋根問祖-Vue的構造函數的出生地
先來一段最常見的vue代碼demo
{{ message }}// js var vm = new Vue({ el: "#app", data: { message: ‘hello vue" } })
上面已經創建了一個vue應用程序;從上面很容易就看出來 Vue是一個構造器,vm是用這個構造器構造出來的實例化對象,實例化的時候傳入了參數,參數中包括el和data
上述延伸了3個問題:
Vue 構造器是什么模樣?
Vm可以使用的方法,即vue的開放API都在源碼里面怎么實現的?
我們傳入構造方法內的參數發生了什么
這些問題是我們解鎖vue源碼的最開始的步驟,所以我們不妨通過vue源碼的入口開始尋找這些源碼的實現
在源碼的src/platforms/web下面放著不同版本的構建entry文件,這些文件中導出export的Vue,都是從src/core/instance/index這個文件import過來的,
我們先看下入口文件能帶給我們什么答案:
// src/core/instance/index 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)
這個入口文件做了3件事:
引用了 ./instance/index, 暴露了vue的來源,即構造器
調用initGlobalAPI方法,將vue傳進去, 給vue拓展了全局靜態方法
將vue暴露出去
這個入口文件的意義,是在暴露vue之前,給vue通過initGlobalAPI方法給vue拓展了全局靜態方法,對應Vue的外部API是 Vue.config,包含了Vue的全局配置,
Vue.config.silent // 日志與警告 Vue.config.errorHandler // 這個處理函數被調用的時候,可以獲取錯誤信息和Vue實例 Vue.config.devtools // 配置是否允許 vue-devtools 檢查代碼 …..從initGlobalAPI方法看Vue.config全局配置
initGlobalAPI方法定義了configDef對象,它的getter方法會的屬性值是config,setter方法給出警告不允許修改。最后在vue上添加了config屬性,屬性描述返回configDef對象
export function initGlobalAPI (Vue: GlobalAPI) { // config const configDef = {} configDef.get = () => config if (process.env.NODE_ENV !== "production") { configDef.set = () => { warn( "Do not replace the Vue.config object, set individual fields instead." ) } } Object.defineProperty(Vue, "config", configDef) // 添加config屬性
除此之外,還定義了util屬性,但是并沒有暴露到外面,也并不建議外部去使用
尋根問祖-Vue的構造函數的出生地了解了構造函數,也就知道了new vue()的時候發生了什么
下面這段代碼就是Vue的構造方法,我們可以直觀的看出vue構造器是使用ES5的Function去實現類,是因為可以通過prototype往vue原型上拓展很多方法,把這些方法拆分到不同的文件/模塊下,這樣更有利于代碼的維護,與協同開發
比如在這個文件中,可以看到把Vue當作一個參數傳進下面的**Mixin方法中,這些方法都是通過接收vue,在它的prototype上面定義一些功能的;
function Vue (options) { if (process.env.NODE_ENV !== "production" && !(this instanceof Vue) ) { warn("Vue is a constructor and should be called with the `new` keyword’) // vue必須是new vue()的實例化對象 } console.log("options", options) this._init(options) // 調用內部_init方法 } initMixin(Vue) // 在created生命周期函數之前的操作 stateMixin(Vue) // 利用 definedProperty 進行靜態數據的訂閱發布 eventsMixin(Vue) // 實例事件流的注入, 利用的是訂閱發布模式的事件流構造 lifecycleMixin(Vue) // renderMixin(Vue) // 實現 _render 渲染虛擬dom export default Vue
這個構造函數的最核心點,就是this._init(options)
在此處打斷點,可以看到參數options傳進來的就是外面我們實例化時傳入的參數el 和 data
new Vue({ el: "#app", data: { message: ‘hello vue" } })
這個_init方法出自initMixin 函數
看完這個函數,我們梳理出整個初始化階段源碼的幾個重要的節點
初始化options參數進行合并配置
初始化生命周期
初始化時間系統
初始化state,包括data、props、 computed、watcher
export function initMixin (Vue: Class
console.log("Vue", Vue) Vue.prototype._init = function (options?: Object) { const vm: Component = this // a uid 實例化的uid遞增1 vm._uid = uid++ let startTag, endTag /* istanbul ignore if */
...
// 用_isVue來標識當前的實例是個Vue實例,這樣做是為了后續被observed vm._isVue = true // 合并配置options,并判斷是否是內部Component的options的初始化 if (options && options._isComponent) { // 內部 initInternalComponent(vm, options) } else { // 非內部 vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) } // 在render中將this指向vm._renderProxy if (process.env.NODE_ENV !== "production") { initProxy(vm) } else { vm._renderProxy = vm } // expose real self vm._self = vm // 初始化生命周期 initLifecycle(vm) // 初始化事件注冊 initEvents(vm) // 初始化渲染 initRender(vm) // 觸發回掉函數中的beforeCreate鉤子函數 callHook(vm, "beforeCreate") initInjections(vm) // resolve injections before data/props // 初始化vm的狀態,包括data、props、computed、watcher等 initState(vm) initProvide(vm) // resolve provide after data/props // vm已經創建好來,回掉created鉤子函數 callHook(vm, "created’) /* istanbul ignore if */ … // 將實例進行掛載 if (vm.$options.el) { vm.$mount(vm.$options.el) } }
}
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109241.html
摘要:用造個組件輪子吧閏土大叔如果你掌握了的組件知識,相關的指令事件,花點時間你也可以造出這么個入門級的小輪子。接下來,拋出造輪子實踐背后帶來的一些思考。以上三部分內容構成了的整個執行過程。 showImg(https://segmentfault.com/img/bV1Tnu?w=754&h=500); 前言 首先,向大家說聲抱歉。由于之前的井底之蛙,誤認為Vue.js還遠沒有覆蓋到二三線...
摘要:構造函數文件路徑初始化這里只拿對例子理解最關鍵的步驟分析。在最后,調用了對數據進行。每個函數之后都會返回一個。就是去實例化指令,將指令和新建的元素在一起,然后將元素替換到中去。 下面的代碼會在頁面上輸出Hello World,但是在這個new Vue()到頁面渲染之間,到底發生了什么。這篇文章希望通過最簡單的例子,去了解Vue源碼過程。這里分析的源碼版本是Vue.version = 1...
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關注公眾號也可以吧原理白話版從模板上使用到掛載到頁面 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于...
摘要:假如你通過閱讀源碼,掌握了對的實現原理,對生態系統有了充分的認識,那你會在面試環節游刃有余,達到晉級阿里的技術功底,從而提高個人競爭力,面試加分更容易拿。 前言 一年一度緊張刺激的高考開始了,與此同時,我也沒閑著,奔走在各大公司的前端面試環節,不斷積累著經驗,一路升級打怪。 最近兩年,太原作為一個準二線城市,各大互聯網公司的技術棧也在升級換代,假如你在太原面試前端崗位,而你的技術庫里若...
摘要:慢慢地,關于的原創學習文章已經寫了多篇了會一直放出來,目前篇,因此做一個合集,獻給那些對新版本腳手架使用和背后設計感興趣的同學,都是一步一步去看源碼,也給官方提了幾次,合進去了幾個原創不易,歡迎大家互相轉發,期望大家一起快速過度到版本目錄 慢慢地,關于 Vue CLI 3 的原創學習文章已經寫了 20 多篇了(會一直放出來,目前 23 篇), 因此做一個合集,獻給那些對新版本腳手架使用...
閱讀 3568·2023-04-26 00:05
閱讀 956·2021-11-11 16:55
閱讀 3529·2021-09-26 09:46
閱讀 3519·2019-08-30 15:56
閱讀 911·2019-08-30 15:55
閱讀 2937·2019-08-30 15:53
閱讀 1948·2019-08-29 17:11
閱讀 817·2019-08-29 16:52