vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue自定义父子组件mounted执行顺序

Vue 先初始化父组件再初始化子组件的方法(自定义父子组件mounted执行顺序)

作者:Dandelion

这篇文章主要介绍了Vue 先初始化父组件再初始化子组件的方法(自定义父子组件mounted执行顺序),本篇内容内容主要讲述了,在使用 Konva 进行开发过程中遇到的一些问题,需要的朋友可以参考下

写在前面:

本篇内容内容主要讲述了,在使用 Konva 进行开发过程中遇到的一些问题。(既然是组件加载顺序,主要牵扯到的就是,父子组件的关系,父子组件的生命周期)

众所周知,Vue中父子组件生命周期的执行顺序为:

// 挂载阶段
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
// 更新阶段
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
// 销毁阶段
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

1、引用关系说明

2、两层继承关系示例

假如说目前我只有两层继承关系,App.vue 和所需组件 Channel.vue

代码在下方展示,详细的内容我将在代码中使用注释详细说明,请按照注释编号顺序进行阅读和理解

App.vue

要点:

<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应当是响应式的,否则对子组件的修改无法同步到父组件的layer
      layer: computed(() => this.layer),      // 4. 响应式的区别,类比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>
    /* 样式细节不表 */
</style>
 
<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更新之后执行回调函数
        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、三层及以上继承关系示例

  • 在上面的内容中,使用this.$nextTick(() => { 回调 })解决了两层继承关系中的反向初始化顺序的问题。
  • 但是这本质上更像是一种小聪明,当到了三层以上继承关系的时候这种方法不能有任何效果,因为子组件和孙子组件如果不同时使用 this.$nextTick(() => { 回调 }) 总会有人在父组件之前初始化,而如果都用了 this.$nextTick(() => { 回调 }) 那么它们两个本身的初始化顺序仍然是先子后父,一定会出问题。所以要使用其他的方式来解决这个问题

代码在下方展示,详细的内容我将在代码中使用注释详细说明,请按照注释编号顺序进行阅读和理解

<template>
    <div>
        <div ref="container"></div>
        <!-- 3. v-if="flag" 控制子组件的初始化时机 -->
        <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,这种传递方式默认为响应式,无需其他操作 -->
        <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. 准备一个flag用于确认初始化时机
            flag: false,
            group: null,
        };
    },
    mounted() {
        // 1. 存在父亲,切需要使用父亲中的 layer ,等待父组件初始化完成
        this.$nextTick(() => {
            this.initializeKonva();
            // 2. 使用flag判断是否已经初始化完成
            this.flag = true;
        });
    },
    methods: {
        initializeKonva() {
            // ...
            this.layer.add(this.group);
            this.layer.draw();
        },
        handleDBChange(newDB) {
            // ...
        },
        handleLevelChange(newLevel) {
            // ...
        },
    },
};
</script>
<style></style>
  

到此这篇关于Vue 先初始化父组件再初始化子组件的方法(自定义父子组件mounted执行顺序)的文章就介绍到这了,更多相关vue自定义父子组件mounted执行顺序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文