Vue?先初始化父組件再初始化子組件的方法(自定義父子組件mounted執(zhí)行順序)
寫(xiě)在前面:
本篇內(nèi)容內(nèi)容主要講述了,在使用 Konva 進(jìn)行開(kāi)發(fā)過(guò)程中遇到的一些問(wèn)題。(既然是組件加載順序,主要牽扯到的就是,父子組件的關(guān)系,父子組件的生命周期)
眾所周知,Vue中父子組件生命周期的執(zhí)行順序?yàn)椋?/p>
// 掛載階段 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted // 更新階段 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated // 銷(xiāo)毀階段 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
然而,在某些情況下我們有其他需求,例如我們不得不讓子組件的初始化在父組件初始化完成之后再進(jìn)行(一般是針對(duì)
mounted),下面將進(jìn)行詳細(xì)說(shuō)明
1、引用關(guān)系說(shuō)明
- 最終目的:使用
Konva庫(kù)繪制組件,該組件由兩個(gè)按鈕、一個(gè)電平表、一個(gè)增益控制推桿,這些子組件組合起來(lái)構(gòu)成所需組件,并將其繪制到Stage中的Layer上Stage和Layer只有一個(gè),所以應(yīng)當(dāng)寫(xiě)在App.vue中,使用時(shí)將Layer傳遞給子組件(且這個(gè)Layer應(yīng)當(dāng)是響應(yīng)式的);且由于要繪制所需組件,因此自然是要引用所需組件,即所需組件是App.vue的子組件- 所需組件應(yīng)當(dāng)引用各個(gè)子組件,它是各個(gè)子組件的父親
- 綜上,是一個(gè)三層的繼承關(guān)系,此外,由于有了
Stage和Layer才能繪制所需組件,有了所需組件才能繪制各個(gè)子組件,此時(shí),各個(gè)控件的初始化順序與生命周期剛好相反。
2、兩層繼承關(guān)系示例
假如說(shuō)目前我只有兩層繼承關(guān)系,
App.vue和所需組件Channel.vue代碼在下方展示,詳細(xì)的內(nèi)容我將在代碼中使用注釋詳細(xì)說(shuō)明,請(qǐng)按照注釋編號(hào)順序進(jìn)行閱讀和理解
App.vue
要點(diǎn):
layer依賴(lài)注入,使所有的子組件可以獲取- 父組件的
layer進(jìn)行依賴(lài)注入時(shí)需要使用響應(yīng)式,以便于父組件知道layer的改變(類(lèi)比C語(yǔ)言的直接傳參和指針傳參) - 需要將所需組件引用、注冊(cè)并展示到頁(yè)面上
<template>
<div id="app">
<div id="frame">
<!-- 7. 將所需子組件展示到頁(yè)面 -->
<Channel />
</div>
</div>
</template>
<script>
import Konva from 'konva';
import { computed } from 'vue';
// 5. 引入所需組件用于繪制和頁(yè)面展示
import Channel from './components/Channel.vue';
export default {
// 2. 父組件將 layer 傳遞給子組件,子組件沒(méi)有 layer 就無(wú)法繪制組件
provide() { // 依賴(lài)注入,所有子組件可獲取
return {
// 3. 傳遞給子組件的 layer應(yīng)當(dāng)是響應(yīng)式的,否則對(duì)子組件的修改無(wú)法同步到父組件的layer
layer: computed(() => this.layer), // 4. 響應(yīng)式的區(qū)別,類(lèi)比C語(yǔ)言的直接傳參和指針傳參
}
},
components: {
// 6. 注冊(cè)子組件
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. 這里為了解耦和效率,全局使用一個(gè)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依賴(lài)注入,使所有的子組件可以獲取- 父組件的
layer進(jìn)行依賴(lài)注入時(shí)需要使用響應(yīng)式,以便于父組件知道layer的改變(類(lèi)比C語(yǔ)言的直接傳參和指針傳參) - 需要將所需組件引用、注冊(cè)并展示到頁(yè)面上
Channel.vue要點(diǎn):
接收
layer使用
this.$nextTick(() => { 初始化代碼 }),會(huì)使得初始化代碼在父組件的初始化完成后再執(zhí)行this.$nextTick()是Vue.js提供的一個(gè)方法,用于在DOM更新之后執(zhí)行回調(diào)函數(shù)。它的作用是確保在下次DOM更新循環(huán)結(jié)束之后執(zhí)行回調(diào)函數(shù),以確保操作的準(zhǔn)確性和可靠性。在
Vue.js中,當(dāng)數(shù)據(jù)發(fā)生改變時(shí),Vue會(huì)異步地更新DOM。這意味著在修改數(shù)據(jù)后立即訪問(wèn)更新后的DOM可能無(wú)法得到正確的結(jié)果,因?yàn)榇藭r(shí)DOM可能尚未完成更新。通過(guò)使用
this.$nextTick()方法,我們可以將回調(diào)函數(shù)延遲到下一次DOM更新循環(huán)之后執(zhí)行。在這個(gè)時(shí)候,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. 接收父組件依賴(lài)注入的 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 是通過(guò)依賴(lài)注入傳遞,inject接收的,使用 this 訪問(wèn)
this.layer.add(this.group);
// 5. 更新 layer
this.layer.draw();
},
},
};
</script>
<style></style>
3、三層及以上繼承關(guān)系示例
- 在上面的內(nèi)容中,使用
this.$nextTick(() => { 回調(diào) })解決了兩層繼承關(guān)系中的反向初始化順序的問(wèn)題。- 但是這本質(zhì)上更像是一種小聰明,當(dāng)?shù)搅巳龑右陨侠^承關(guān)系的時(shí)候這種方法不能有任何效果,因?yàn)樽咏M件和孫子組件如果不同時(shí)使用
this.$nextTick(() => { 回調(diào) })總會(huì)有人在父組件之前初始化,而如果都用了this.$nextTick(() => { 回調(diào) })那么它們兩個(gè)本身的初始化順序仍然是先子后父,一定會(huì)出問(wèn)題。所以要使用其他的方式來(lái)解決這個(gè)問(wèn)題代碼在下方展示,詳細(xì)的內(nèi)容我將在代碼中使用注釋詳細(xì)說(shuō)明,請(qǐng)按照注釋編號(hào)順序進(jìn)行閱讀和理解
Channel.vue
要點(diǎn):
- 接收
layer等不再贅述 - 使用
this.$nextTick(() => { 初始化代碼 }),會(huì)使得初始化代碼在父組件的初始化完成后再執(zhí)行 - 設(shè)置
flag用于判斷當(dāng)前組件初始化是否完成,使用v-if="flag"控制子組件初始化時(shí)機(jī)
- 接收
<template>
<div>
<div ref="container"></div>
<!-- 3. v-if="flag" 控制子組件的初始化時(shí)機(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)式,無(wú)需其他操作 -->
<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)備一個(gè)flag用于確認(rèn)初始化時(shí)機(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue?Router嵌套路由(children)的用法小結(jié)
嵌套路由就是父路由里面嵌套他的子路由,父路由有自己的路由導(dǎo)航和路由容器(router-link、router-view),通過(guò)配置children可實(shí)現(xiàn)多層嵌套,這篇文章主要介紹了Vue--Router--嵌套路由(children)的用法,需要的朋友可以參考下2022-08-08
Vue如何監(jiān)測(cè)數(shù)組類(lèi)型數(shù)據(jù)發(fā)生改變的(推薦)
這篇文章主要介紹了Vue如何監(jiān)測(cè)數(shù)組類(lèi)型數(shù)據(jù)發(fā)生改變的,本文通過(guò)實(shí)例代碼圖文詳解給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11
vue使用SVG實(shí)現(xiàn)圓形進(jìn)度條音樂(lè)播放
這篇文章主要為大家詳細(xì)介紹了vue使用SVG實(shí)現(xiàn)圓形進(jìn)度條音樂(lè)播放,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
vue-calendar-component日歷組件報(bào)錯(cuò)Clock is not defi
這篇文章主要為大家介紹了vue-calendar-component日歷組件報(bào)錯(cuò)Clock is not defined解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
vue監(jiān)聽(tīng)滾動(dòng)事件的方法
這篇文章主要介紹了vue監(jiān)聽(tīng)滾動(dòng)事件的方法,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下2020-12-12
vue中全局路由守衛(wèi)中替代this操作(this.$store/this.$vux)
這篇文章主要介紹了vue中全局路由守衛(wèi)中替代this操作(this.$store/this.$vux),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
vue3響應(yīng)式Object代理對(duì)象的讀取示例詳解
這篇文章主要為大家介紹了vue3響應(yīng)式Object代理對(duì)象的讀取示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
如何使用Vue3.2+Vite2.7從0快速打造一個(gè)UI組件庫(kù)
構(gòu)建工具使用vue3推薦的vite,下面這篇文章主要給大家介紹了關(guān)于如何使用Vue3.2+Vite2.7從0快速打造一個(gè)UI組件庫(kù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09

