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上Stage和Layer只有一个,所以应当写在App.vue中,使用时将Layer传递给子组件(且这个Layer应当是响应式的);且由于要绘制所需组件,因此自然是要引用所需组件,即所需组件是App.vue的子组件- 所需组件应当引用各个子组件,它是各个子组件的父亲
- 综上,是一个三层的继承关系,此外,由于有了
Stage和Layer才能绘制所需组件,有了所需组件才能绘制各个子组件,此时,各个控件的初始化顺序与生命周期刚好相反。
2、两层继承关系示例
假如说目前我只有两层继承关系,
App.vue和所需组件Channel.vue代码在下方展示,详细的内容我将在代码中使用注释详细说明,请按照注释编号顺序进行阅读和理解
App.vue要点:
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执行顺序)的更多相关文章
- 二、Vue组件(component):组件的相互引用、通过props实现父子组件互传值
一.组件各部分说明及互相引用 1.一个vue组件由三个部分组成 Template 只能存在一个根元素 2.Script 3.Style scoped:样式只在当前组件内生效 1.1 组件的基本引用代码 ...
- 子元素使用float 父元素撑开方法
一个Div包含了多个子Div,并且子Div使用了浮动后,父Div确不能被撑开,如下图: 部分代码如下: 1 <style> 2 #div1{border:1px solid red;f ...
- 【转】C# 子窗体如何调用父窗体的方法
网络上有几种方法,先总结如下: 调用窗体(父):FormFather,被调用窗体(子):FormSub. 方法1: 所有权法 //FormFather: //需要有一个公共的 ...
- 【转】WPF查找子控件和父控件方法
一.查找某种类型的子控件,并返回一个List集合 public List<T> GetChildObjects<T>(DependencyObject obj, Type ty ...
- WPF查找子控件和父控件方法
一.查找某种类型的子控件,并返回一个List集合 public List<T> GetChildObjects<T>(DependencyObject obj, Type ty ...
- 【转】vue父子组件之间的通信
vue父子组件之间的通信 在vue组件通信中其中最常见通信方式就是父子组件之中的通性,而父子组件的设定方式在不同情况下又各有不同.最常见的就是父组件为控制组件子组件为视图组件.父组件传递数据给子组件使 ...
- 关于vue.js父子组件数据传递
vue.js中使用props down,events up的原则进行父子组件间的通信,先来记录下props down,看个例子: <div id="app2"> < ...
- vue组件之间的传值——中央事件总线与跨组件之间的通信($attrs、$listeners)
vue组件之间的通信有很多种方式,最常用到的就是父子组件之间的传值,但是当项目工程比较大的时候,就会出现兄弟组件之间的传值,跨级组件之间的传值.不可否认,这些都可以类似父子组件一级一级的转换传递,但是 ...
- vue组件通信之父子组件通信
准备工作: 首先,新建一个项目,如果这里有不会的同学,可以参考我转载过的文章 http://www.cnblogs.com/Sky-Ice/p/8875958.html vue 脚手架安装及新建项目 ...
- Vue 非父子组件通信方案
Vue 非父子组件通信方案 概述 在 Vue 中模块间的通信很普遍 如果是单纯的父子组件间传递信息,父组件可以使用 props 将数据向下传递到子组件,而在子组件中可以使用 events (父组件需要 ...
随机推荐
- 2.自定义@Excel注解实现数据Excel形式导入导出
前言 这几天在学习如何使用自定义注解实现Excel格式数据导入导出,参考的还是若依框架里面的代码,由于是初学,所以照猫画虎呗,但是难受的是需要复制并根据自己项目修改作者自定义的工具类以及导入这些工具类 ...
- Numpy数组乘法
Numpy数组乘法 元素级乘法 numpy.multiply() 或 * : 数组对应位置元素相乘 import numpy as np # 一维数组 a = np.array([1, 2, 3, 4 ...
- Spring中Bean的实例化详细流程
还是举个例子,我有一个朋友小汪他远赴南方某城市打工.然后安定下来后他的朋友很想来家里玩,但是呢我这个朋友家里搞的很乱,所以他不好意思请朋友来家里玩.这时我的另一个朋友说那请一个保姆把家里好好整理一下就 ...
- mariabackup -prepare step on increment backup failed
问题描述:使用mariabackup对maridb10.6.4进行物理备份,进行增量恢复的时候报错.截止到目前,还是mariadb的一个bug,还没有修复.在增备的过程中如果出现新库的建立,数据库就会 ...
- vs的常用配置【以及vs常用的快捷键】
1.颜色设置 (1) 编译器的主题颜色设置 (2) 字体和颜色设置 (3) 字体大小 更快捷的修改字体大小方式:ctr+鼠标滚轮 2.行号设置 默认就有,不用设置了 3.把解决方案资源管理器移动到左边 ...
- 用Abp实现找回密码和密码强制过期策略
@ 目录 重置密码 找回密码 发送验证码 校验验证码 发送重置密码链接 创建接口 密码强制过期策略 改写接口 Vue网页端开发 重置密码页面 忘记密码控件 密码过期提示 项目地址 用户找回密码,确切地 ...
- Go Home
Go Home (https://www.luogu.com.cn/problem/AT_arc070_a) 比较需要理解题意的一个题目 看看题目解析:在0秒的时候有一只袋鼠在左右无限长的数轴上的原点 ...
- win11 计算器的进制转换
- 2021-08-16:回文对。给定一组 互不相同 的单词, 找出所有 不同 的索引对 (i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串。
2021-08-16:回文对.给定一组 互不相同 的单词, 找出所有 不同 的索引对 (i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串. 福大大 答案20 ...
- Django中render()函数和redirect()函数
render() 作用:render是渲染变量(结合一个给定的模板和一个给定的上下文字典)在模板中,通俗点将context的内容,加载进模板中定义的文件,通过浏览器渲染呈现. render()方法常用 ...