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

这篇具有很好参考价值的文章主要介绍了Vue 先初始化父组件再初始化子组件的方法(自定义父子组件mounted执行顺序)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面:

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

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

    // 挂载阶段
    父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
    
    // 更新阶段
    父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
    
    // 销毁阶段
    父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
    
  • 然而,在某些情况下我们有其他需求,例如我们不得不让子组件的初始化在父组件初始化完成之后再进行(一般是针对mounted),下面将进行详细说明

1、引用关系说明

  • 最终目的:使用Konva 库绘制组件,该组件由两个按钮、一个电平表、一个增益控制推杆,这些子组件组合起来构成所需组件,并将其绘制到Stage中的Layer
    • StageLayer只有一个,所以应当写在App.vue中,使用时将Layer传递给子组件(且这个Layer应当是响应式的);且由于要绘制所需组件,因此自然是要引用所需组件,即所需组件是App.vue的子组件
    • 所需组件应当引用各个子组件,它是各个子组件的父亲
  • 综上,是一个三层的继承关系,此外,由于有了StageLayer才能绘制所需组件,有了所需组件才能绘制各个子组件,此时,各个控件的初始化顺序与生命周期刚好相反

2、两层继承关系示例

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

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

  • App.vue

    要点:文章来源地址https://www.toymoban.com/news/detail-525649.html

    • layer 依赖注入,使所有的子组件可以获取
    • 父组件的 layer 进行依赖注入时需要使用响应式,以便于父组件知道 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应当是响应式的,否则对子组件的修改无法同步到父组件的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>
    
    
  • Channel.vue

    要点:

    • 接收 layer

    • 使用 this.$nextTick(() => { 初始化代码 }),会使得初始化代码在父组件的初始化完成后再执行

      • this.$nextTick()Vue.js提供的一个方法,用于在DOM更新之后执行回调函数。它的作用是确保在下次DOM更新循环结束之后执行回调函数,以确保操作的准确性和可靠性。

      • Vue.js中,当数据发生改变时,Vue会异步地更新DOM。这意味着在修改数据后立即访问更新后的DOM可能无法得到正确的结果,因为此时DOM可能尚未完成更新。

        通过使用this.$nextTick()方法,我们可以将回调函数延迟到下一次DOM更新循环之后执行。在这个时候,Vue已经完成了所有的异步DOM更新,我们可以放心地操作更新后的DOM元素,确保获取到准确的结果。

    • 绘制完成后更新 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更新之后执行回调函数
            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(() => { 回调 }) 那么它们两个本身的初始化顺序仍然是先子后父,一定会出问题。所以要使用其他的方式来解决这个问题

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

  • Channel.vue

    要点:

    • 接收 layer 等不再赘述
    • 使用 this.$nextTick(() => { 初始化代码 }),会使得初始化代码在父组件的初始化完成后再执行
    • 设置flag用于判断当前组件初始化是否完成,使用v-if="flag"控制子组件初始化时机
    <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执行顺序)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue中初始化

    主要是挂载一些全局方法 响应数据相关的Vue.set, Vue.delete, Vue.nextTick以及Vue.observable 插件相关的Vue.use 对象合并相关Vue.mixin 类继承相关的Vue.extend 资源相关,如组件,过滤器,自定义指令Vue.component, Vue.filter, Vue.directive 配置相关Vue.config以及Vue.options中的components,filters,directives 定

    2023年04月22日
    浏览(33)
  • Android 自定义view 中增加属性,初始化时读取

    因为自定义View 有正向和反向两个状态,所以需要在初始化时区分加载哪个layout 在Android中,要在自定义View中增加属性,你需要完成以下步骤: 在res/values/attrs.xml文件中定义属性。 在自定义View的构造函数中获取这些属性。 在布局文件中使用这些属性。 attrs.xml: 自定义VIEW 中

    2024年04月25日
    浏览(28)
  • cv库学习,一 Mat类矩阵的定义初始化

    1,由多维数组定义初始化Mat类矩阵;      double m[2][2]={{1.0,2.0},{3.0,4.0}};       Mat M(2,2,CV_64F,m); 2,构造函数定义法      Mat M(2,2,CV_32FC3,Scalar(100,200,300));       Mat M(2,2,CV_32FC2,Scalar(100,200));       Mat M(2,2,CV_8UC1,Scalar(100)); 3,   M.create(Size(10, 20), CV_32FC3); 在原有的M矩阵上修改大

    2023年04月24日
    浏览(28)
  • Vue初始化项目加载逻辑

    项目创建 我们只需要创建项目即可,剩余的依赖都没必要安装 我们先来看main.js,咱们加了一行备注 通过备注可知,我们首先加载的是App.vue 我们再来看一下App.vue 里都有啥 也就是下面这个红框里的内容才是 那下面的内容是哪里来的呢 那就需要看一下路由设置了 我们看到/目

    2024年02月08日
    浏览(88)
  • C语言——结构体类型(一)【结构体定义,创建,初始化和引用】

    📝前言: 在实际编程过程中,我们可能会希望把一些关联的数据存放在一起,这样方便我们使用。但是这些数据的类型有时候并不一致,例如一个学生的信息:有名字(字符串),有年龄(整数),性别(字符)······这时候,我们就可以使用 自定义类型——结构体类型

    2024年02月03日
    浏览(37)
  • Set的初始化方法

    定义了一个Set后,我想把它初始化一下. 这种初始化的方法,比第一种要简单一些,利用的有两个Java知识点,一个是匿名内部类,一个是实例初始化块。 补充:对于这样的匿名类,是无法获取它的对象的。

    2024年02月11日
    浏览(25)
  • 1、前端项目初始化(vue3)

    安装npm,(可以用nvm管理npm版本)npm安装需要安装node.js(绑定销售?)而使用nvm就可以很方便的下载不同版本的node,这里是常用命令 配置npm源 命令: 设置镜像源: npm config set registry https://registry.npm.taobao.org 查看当前使用的镜像地址: npm config get registry 参考 :https://www.cnbl

    2024年01月20日
    浏览(43)
  • Vue 新版 脚手架 初始化 笔记

    Vue2/Vue3 修改 node 更新源 将默认的 更新源修改为 淘宝的 下载地址 安装 一般 新版 Vue 脚手架不可以共存 所以如果有 旧版的脚手架 会提示你 需要卸载 原来的脚手架 然后重新执行上面的安装 安装好之后 就可以去初始化项目了 值得一提的是我在官方的文档中找到了一个 在使

    2024年02月20日
    浏览(27)
  • 神经网络的初始化方法

    对于神经网络的训练过程中,合适的参数初始化方法有助于更好的处理梯度消失和梯度爆炸问题。 通常有以下几种初始化方法: 随机初始化(Random Initialization):最简单的初始化方法是随机生成参数的初始值。可以根据一定的分布(如均匀分布或正态分布)从一个较小的范

    2024年02月15日
    浏览(33)
  • C++结构体初始化方法

    在 C++ 里可以将结构体看作没有任何成员函数的对象,下面对 C++ 结构体的几种初始化方法进行总结。 如果只是想全部初始化为 0 可以按照如下方法 结构体包含数组(数组在结构体变量定义完就初始化为0) 直接赋值的方法虽然很直观,但是如果需要初始化多个结构体变量,

    2024年02月16日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包