詳解Vue 2中的? initState 狀態(tài)初始化
initState 狀態(tài)初始化
在配置標準化合并以及聲明周期初始化完成之后,會調(diào)用 callHook('beforeCreate') 來表示組件已進入正式實例化階段。
這個時候會對數(shù)據(jù)、方法、監(jiān)聽器等配置項進行對應的處理,并且在開發(fā)環(huán)境還會進行一系列校驗,拋出校驗異常信息。整個數(shù)據(jù)的初始化過程是 initInjection => initState => initProvide,但是 injection/provide 一般是一起使用,所以這里也替換一下順序,將這兩者放到后面一起分析。
首先是 initState 的函數(shù)定義:
?export function initState(vm: Component) {
? ?const opts = vm.$options
? ?if (opts.props) initProps(vm, opts.props)
? ?// Composition API
? ?initSetup(vm)
? ?if (opts.methods) initMethods(vm, opts.methods)
? ?if (opts.data) {
? ? ?initData(vm)
? } else {
? ? ?const ob = observe((vm._data = {}))
? ? ?ob && ob.vmCount++
? }
? ?if (opts.computed) initComputed(vm, opts.computed)
? ?if (opts.watch && opts.watch !== nativeWatch) {
? ? ?initWatch(vm, opts.watch)
? }
?}整個過程其實十分清晰:
- initProps:初始化 props 組件參數(shù)配置
- initSetup:解析 setup 配置,處理 setup 的返回值(這里主要是 2.7 版本之后為了適配 v3 語法新增的內(nèi)容)
- initMethods:初始化組件方法
- initData:初始化組件內(nèi)變量
- initComputed:初始化組件計算屬性
- initWatch:初始化組件內(nèi)部監(jiān)聽器
1. initProps
該函數(shù)定義如下:
?function initProps(vm: Component, propsOptions: Object) {
? ?const propsData = vm.$options.propsData || {}
? ?const props = (vm._props = shallowReactive({}))
? ?const keys: string[] = (vm.$options._propKeys = [])
? ?const isRoot = !vm.$parent
? ?
? ?if (!isRoot) {
? ? ?toggleObserving(false)
? }
? ?for (const key in propsOptions) {
? ? ?keys.push(key)
? ? ?const value = validateProp(key, propsOptions, propsData, vm)
? ? ?if (__DEV__) {
? ? ? ?const hyphenatedKey = hyphenate(key)
? ? ? ?if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) {
? ? ? ? ?warn('')
? ? ? }
? ? ? ?defineReactive(props, key, value, () => {
? ? ? ? ?if (!isRoot && !isUpdatingChildComponent) {
? ? ? ? ? ?warn('')
? ? ? ? }
? ? ? })
? ? } else {
? ? ? ?defineReactive(props, key, value)
? ? }
? ? ?if (!(key in vm)) {
? ? ? ?proxy(vm, `_props`, key)
? ? }
? }
? ?toggleObserving(true)
?}這個過程會遍歷整個組件的 props 配置項(mergeOptions 之后,已包含繼承和混入),并將每個 prop key 從駝峰形式轉(zhuǎn)換為 - 短橫線連接的形式。
這也是為什么官方推薦 props 配置使用 小寫駝峰,而組件使用時綁定參數(shù)使用 - 短橫線 的原因。
之后,則是校驗每個 prop 的 key 是否符合規(guī)范(即不是 Vue 的內(nèi)置關(guān)鍵字 ref,key 等,也是不是配置里面 isReservedAttr(key) 禁止的屬性名);最后,通過 defineReactive 來對 prop 進行響應式處理,并掛載到 vm._props 中。
當然,上面的響應式處理 只針對根組件,如果不是根組件的話,是會在函數(shù)前面部分調(diào)用 toggleObserving(false) 來關(guān)閉響應式處理
2. initSetup
這個部分是為了適配 v3 語法新增的一部分,這里就不放源碼,只簡單介紹一下。
該方法位于 src/v3/apiSetup.ts 文件內(nèi),在執(zhí)行過程中,主要有以下幾步:
- 通過 createSetupContext(vm) 創(chuàng)建一個 setup 函數(shù)執(zhí)行過程中的上下文對象,該對象包括 attrs,listeners,slots,emit 幾個屬性,以及一個 expose 方法;然后將這個上下文對象綁定到組件的 _setupContext 屬性上,最后調(diào)用 setCurrentInstance 將當前上下文實例指定為當前組件實例 vm
- 調(diào)用 pushTarget() 阻止過程中的依賴收集,并調(diào)用 invokeWithErrorHandling 來獲取 setup 函數(shù)的返回值
- 然后刪除 setup 中的當前實例上下文,調(diào)用 popTarget 恢復依賴收集
- 判斷 setup 函數(shù)的執(zhí)行返回值,如果是函數(shù),則說明返回的是 render,將該返回值賦值給 options 用于后面執(zhí)行 mount 渲染;如果是對象,則會將返回值賦值給 vm._setupState,然后遍歷返回值對象,進行響應式處理
3. initMethods
函數(shù)定義如下:
?function initMethods(vm: Component, methods: Object) {
? ?const props = vm.$options.props
? ?for (const key in methods) {
? ? ?if (__DEV__) {
? ? ? ?if (typeof methods[key] !== 'function') {
? ? ? ? ?warn('')
? ? ? }
? ? ? ?if (props && hasOwn(props, key)) {
? ? ? ? ?warn('')
? ? ? }
? ? ? ?if (key in vm && isReserved(key)) {
? ? ? ? ?warn('')
? ? ? }
? ? }
? ? ?vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
? }
?}這部分就十分十分簡單了,就是通過 Function.bind 函數(shù)來更改組件配置 options 中的每一個方法的 this 指向,最后重新綁定到當前組件上。
這里的校驗其實就是校驗名字是否會和 js 的內(nèi)置方法名沖突,或者與 props 中存在同名方法。
4. initData
在執(zhí)行 initData 之前,會校驗 options 中有沒有 data 配置,沒有則會初始化為一個空對象。
其函數(shù)定義如下:
?function initData(vm: Component) {
? ?let data: any = vm.$options.data
? ?data = vm._data = isFunction(data) ? getData(data, vm) : data || {}
? ?if (!isPlainObject(data)) {
? ? ?data = {}
? ? ?__DEV__ && warn('')
? }
? ?const keys = Object.keys(data)
? ?const props = vm.$options.props
? ?const methods = vm.$options.methods
? ?let i = keys.length
? ?while (i--) {
? ? ?const key = keys[i]
? ? ?if (__DEV__) {
? ? ? ?if (methods && hasOwn(methods, key)) {
? ? ? ? ?warn('')
? ? ? }
? ? }
? ? ?if (props && hasOwn(props, key)) {
? ? ? ?__DEV__ && warn()
? ? } else if (!isReserved(key)) {
? ? ? ?proxy(vm, `_data`, key)
? ? }
? }
? ?const ob = observe(data)
? ?ob && ob.vmCount++
?}這里其實也比較簡單,就是校驗是否有與 props 或者 methods 同名的數(shù)據(jù),并將其代理到 vm._data 上,最后通過 observe 方法對數(shù)據(jù)進行響應式處理。
5. initComputed 與 initWatch
這兩部分主要是配置對 data 與 props 的變量的 變化偵測(監(jiān)聽) ,因為涉及到 Vue 的響應式系統(tǒng)中的 Watcher 觀察者定義 與 依賴收集系統(tǒng),整體的內(nèi)容比較多,所以后面整體講。
簡單分析兩者的基本邏輯:
initComputed:
- 獲取 options.computed 里定義的每個計算屬性的 get 方法作為 getter(如果就是一個函數(shù),則這個函數(shù)直接作為 getter)
- 如果該計算屬性的 key 不能在當前的實例上找到,則直接通過 defineComputed 定義一個計算屬性
- 如果能找到,則判斷是否是在 data,methods,props 中,并報出對應錯誤
initWatch:
這個過程則更加簡單,因為不用校驗 key 的重復性,所以會直接遍歷 options.watch,如果某個屬性的監(jiān)聽器有兩個 handler 方法,還會將方法提出來,最后調(diào)用 createWatcher 來創(chuàng)建監(jiān)聽器。
到此這篇關(guān)于詳解Vue 2中的 initState 狀態(tài)初始化的文章就介紹到這了,更多相關(guān)Vue initState 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue實現(xiàn)多組關(guān)鍵詞對應高亮顯示功能
最近小編遇到這樣的問題,多組關(guān)鍵詞,這里實現(xiàn)了關(guān)鍵詞的背景色與匹配值的字體顏色值相同,下面通過定義關(guān)鍵詞匹配改變字體顏色,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧2019-07-07
vuex根據(jù)不同的用戶權(quán)限展示不同的路由列表功能
最近接到一個新的需求,要求將系統(tǒng)的用戶進行分類,用戶登陸后根據(jù)不同的用戶權(quán)限展示不同的功能列表。這篇文章主要介紹了vuex根據(jù)不同的用戶權(quán)限展示不同的路由列表,需要的朋友可以參考下2019-09-09
vuex如何在非組件中調(diào)用mutations方法
這篇文章主要介紹了vuex如何在非組件中調(diào)用mutations方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
vue Element UI 解決表格數(shù)據(jù)不更新問題及解決方案
在使用Vue和ElementUI開發(fā)后臺管理系統(tǒng)時,可能會遇到表格數(shù)據(jù)不更新的問題,這通常是因為Vue的響應式系統(tǒng)未檢測到數(shù)據(jù)變化或數(shù)據(jù)更新后未正確觸發(fā)視圖的重新渲染,本文給大家介紹vue Element UI 解決表格數(shù)據(jù)不更新問題,感興趣的朋友一起看看吧2024-10-10

