Vue?先初始化父組件再初始化子組件的方法(自定義父子組件mounted執(zhí)行順序)
寫在前面:
本篇內(nèi)容內(nèi)容主要講述了,在使用 Konva
進(jìn)行開發(fā)過程中遇到的一些問題。(既然是組件加載順序,主要牽扯到的就是,父子組件的關(guān)系,父子組件的生命周期)
眾所周知,Vue
中父子組件生命周期的執(zhí)行順序?yàn)椋?/p>
// 掛載階段 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted // 更新階段 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated // 銷毀階段 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
然而,在某些情況下我們有其他需求,例如我們不得不讓子組件的初始化在父組件初始化完成之后再進(jìn)行(一般是針對
mounted
),下面將進(jìn)行詳細(xì)說明
1、引用關(guān)系說明
- 最終目的:使用
Konva
庫繪制組件,該組件由兩個按鈕、一個電平表、一個增益控制推桿,這些子組件組合起來構(gòu)成所需組件,并將其繪制到Stage
中的Layer
上Stage
和Layer
只有一個,所以應(yīng)當(dāng)寫在App.vue中,使用時將Layer
傳遞給子組件(且這個Layer應(yīng)當(dāng)是響應(yīng)式的);且由于要繪制所需組件,因此自然是要引用所需組件,即所需組件是App.vue的子組件- 所需組件應(yīng)當(dāng)引用各個子組件,它是各個子組件的父親
- 綜上,是一個三層的繼承關(guān)系,此外,由于有了
Stage
和Layer
才能繪制所需組件,有了所需組件才能繪制各個子組件,此時,各個控件的初始化順序與生命周期剛好相反。
2、兩層繼承關(guān)系示例
假如說目前我只有兩層繼承關(guān)系,
App.vue
和所需組件Channel.vue
代碼在下方展示,詳細(xì)的內(nèi)容我將在代碼中使用注釋詳細(xì)說明,請按照注釋編號順序進(jìn)行閱讀和理解
App.vue
要點(diǎn):
layer
依賴注入,使所有的子組件可以獲取- 父組件的
layer
進(jìn)行依賴注入時需要使用響應(yīng)式,以便于父組件知道layer
的改變(類比C語言的直接傳參和指針傳參) - 需要將所需組件引用、注冊并展示到頁面上
<template> <div id="app"> <div id="frame"> <!-- 7. 將所需子組件展示到頁面 --> <Channel /> </div> </div> </template> <script> import Konva from 'konva'; import { computed } from 'vue'; // 5. 引入所需組件用于繪制和頁面展示 import Channel from './components/Channel.vue'; export default { // 2. 父組件將 layer 傳遞給子組件,子組件沒有 layer 就無法繪制組件 provide() { // 依賴注入,所有子組件可獲取 return { // 3. 傳遞給子組件的 layer應(yīng)當(dāng)是響應(yīng)式的,否則對子組件的修改無法同步到父組件的layer layer: computed(() => this.layer), // 4. 響應(yīng)式的區(qū)別,類比C語言的直接傳參和指針傳參 } }, components: { // 6. 注冊子組件 Channel, }, mounted() { // 0.初始化組件 this.initializeKonva(); window.addEventListener("resize", this.handleResize); }, beforeUnmount() { window.removeEventListener("resize", this.handleResize); }, data() { return { stage: null, layer: null, }; }, methods: { initializeKonva() { this.stage = new Konva.Stage({ container: "frame", width: window.innerWidth, height: window.innerHeight, }); // 1. 這里為了解耦和效率,全局使用一個layer this.layer = new Konva.Layer(); this.stage.add(this.layer); }, handleResize() { this.stage.width(window.innerWidth); this.stage.height(window.innerHeight); this.stage.batchDraw(); }, }, }; </script> <style scoped> /* 樣式細(xì)節(jié)不表 */ </style>
layer
依賴注入,使所有的子組件可以獲取- 父組件的
layer
進(jìn)行依賴注入時需要使用響應(yīng)式,以便于父組件知道layer
的改變(類比C語言的直接傳參和指針傳參) - 需要將所需組件引用、注冊并展示到頁面上
Channel.vue
要點(diǎn):
接收
layer
使用
this.$nextTick(() => { 初始化代碼 })
,會使得初始化代碼在父組件的初始化完成后再執(zhí)行this.$nextTick()
是Vue.js
提供的一個方法,用于在DOM更新之后執(zhí)行回調(diào)函數(shù)。它的作用是確保在下次DOM
更新循環(huán)結(jié)束之后執(zhí)行回調(diào)函數(shù),以確保操作的準(zhǔn)確性和可靠性。在
Vue.js
中,當(dāng)數(shù)據(jù)發(fā)生改變時,Vue
會異步地更新DOM
。這意味著在修改數(shù)據(jù)后立即訪問更新后的DOM
可能無法得到正確的結(jié)果,因?yàn)榇藭rDOM
可能尚未完成更新。通過使用
this.$nextTick()
方法,我們可以將回調(diào)函數(shù)延遲到下一次DOM
更新循環(huán)之后執(zhí)行。在這個時候,Vue
已經(jīng)完成了所有的異步DOM
更新,我們可以放心地操作更新后的DOM
元素,確保獲取到準(zhǔn)確的結(jié)果。
繪制完成后更新
layer
<template> <div> <div ref="container"></div> </div> </template> <script> import Konva from 'konva'; export default { // 1. 接收父組件依賴注入的 layer inject: ['layer'], components: {}, data() {return {};}, mounted() { // 2. 使用 this.$nextTick(() => {}),在DOM更新之后執(zhí)行回調(diào)函數(shù) this.$nextTick(() => { // 3. 初始化 this.initializeKonva(); }); }, methods: { initializeKonva() { this.group = new Konva.Group({ // ... }); const backgroundRect = new Konva.Rect({ // ... }); const textTop = new Konva.Text({ // ... }); this.textLevel = new Konva.Text({ // ... }); this.textGain = new Konva.Text({ // ... }); const textBottom = new Konva.Text({ // ... }); const line1 = new Konva.Line({ // ... }); const line2 = new Konva.Line({ // ... }); const line3 = new Konva.Line({ // ... }); this.group.add(backgroundRect, textTop, this.textLevel, this.textGain, textBottom, line1, line2, line3); // 4. layer 是通過依賴注入傳遞,inject接收的,使用 this 訪問 this.layer.add(this.group); // 5. 更新 layer this.layer.draw(); }, }, }; </script> <style></style>
3、三層及以上繼承關(guān)系示例
- 在上面的內(nèi)容中,使用
this.$nextTick(() => { 回調(diào) })
解決了兩層繼承關(guān)系中的反向初始化順序的問題。- 但是這本質(zhì)上更像是一種小聰明,當(dāng)?shù)搅巳龑右陨侠^承關(guān)系的時候這種方法不能有任何效果,因?yàn)樽咏M件和孫子組件如果不同時使用
this.$nextTick(() => { 回調(diào) })
總會有人在父組件之前初始化,而如果都用了this.$nextTick(() => { 回調(diào) })
那么它們兩個本身的初始化順序仍然是先子后父,一定會出問題。所以要使用其他的方式來解決這個問題代碼在下方展示,詳細(xì)的內(nèi)容我將在代碼中使用注釋詳細(xì)說明,請按照注釋編號順序進(jìn)行閱讀和理解
Channel.vue
要點(diǎn):
- 接收
layer
等不再贅述 - 使用
this.$nextTick(() => { 初始化代碼 })
,會使得初始化代碼在父組件的初始化完成后再執(zhí)行 - 設(shè)置
flag
用于判斷當(dāng)前組件初始化是否完成,使用v-if="flag"
控制子組件初始化時機(jī)
- 接收
<template> <div> <div ref="container"></div> <!-- 3. v-if="flag" 控制子組件的初始化時機(jī) --> <SwitchButton :btnNameIndex="0" :x="0" :y="group.height() / 17 + group.height() / 17 / 4" :parent="this.group" v-if="flag" /> <SwitchButton :btnNameIndex="1" :x="0" :y="group.height() / 17 * 3 - group.height() / 17 / 3" :parent="this.group" v-if="flag" /> <!-- 4. :parent="this.group" 將this.group傳遞給子組件,命名為parent,這種傳遞方式默認(rèn)為響應(yīng)式,無需其他操作 --> <LevelMeter :x="0" :y="group.height() / 17 * 4 + group.height() / 17 / 2" :parent="this.group" v-if="flag" @levelChangeEvent="handleLevelChange" /> <Gain :x="0" :y="group.height() / 17 * 4 + group.height() / 17 / 4" :parent="this.group" v-if="flag" @dBChangeEvent="handleDBChange" /> </div> </template> <script> import Konva from 'konva'; import SwitchButton from './SwitchButton.vue'; import LevelMeter from './LevelMeter.vue'; import Gain from './Gain.vue'; export default { inject: ['layer'], components: { SwitchButton, LevelMeter, Gain, }, data() { return { // ... // 0. 準(zhǔn)備一個flag用于確認(rèn)初始化時機(jī) flag: false, group: null, }; }, mounted() { // 1. 存在父親,切需要使用父親中的 layer ,等待父組件初始化完成 this.$nextTick(() => { this.initializeKonva(); // 2. 使用flag判斷是否已經(jīng)初始化完成 this.flag = true; }); }, methods: { initializeKonva() { // ... this.layer.add(this.group); this.layer.draw(); }, handleDBChange(newDB) { // ... }, handleLevelChange(newLevel) { // ... }, }, }; </script> <style></style>
到此這篇關(guān)于Vue 先初始化父組件再初始化子組件的方法(自定義父子組件mounted執(zhí)行順序)的文章就介紹到這了,更多相關(guān)vue自定義父子組件mounted執(zhí)行順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue中的methods、watch、computed的區(qū)別
這篇文章主要介紹了Vue中的methods、watch、computed的區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11vue與iframe頁面數(shù)據(jù)互相通信的實(shí)現(xiàn)示例
這篇文章主要給大家介紹了vue與iframe頁面數(shù)據(jù)互相通信的實(shí)現(xiàn)示例,文中通過代碼示例給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-12-12vue動態(tài)配置模板 ''component is''代碼
這篇文章主要介紹了vue動態(tài)配置模板 'component is'代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07Vue引入并使用Element組件庫的兩種方式小結(jié)
本文主要介紹了Vue引入并使用Element組件庫的兩種方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01