- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
写在前面:
本篇内容内容主要讲述了,在使用 Konva 进行开发过程中遇到的一些问题。(既然是组件加载顺序,主要牵扯到的就是,父子组件的关系,父子组件的生命周期) 。
众所周知, Vue 中父子组件生命周期的执行顺序为:
// 挂载阶段 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted // 更新阶段 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated // 销毁阶段 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
然而,在某些情况下我们有其他需求,例如我们不得不 让子组件的初始化在父组件初始化完成之后再进行 (一般是针对 mounted ),下面将进行详细说明 。
Konva
库绘制组件,该组件由两个按钮、一个电平表、一个增益控制推杆,这些子组件组合起来构成所需组件,并将其绘制到 Stage
中的 Layer
上
Stage
和 Layer
只有一个,所以应当写在App.vue中,使用时将 Layer
传递给子组件 (且这个Layer应当是响应式的) ;且由于要绘制所需组件,因此自然是要引用所需组件,即所需组件是App.vue的子组件 Stage
和 Layer
才能绘制所需组件,有了所需组件才能绘制各个子组件,此时, 各个控件的初始化顺序与生命周期刚好相反 。 假如说目前我只有两层继承关系, 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>
- 在上面的内容中,使用
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先初始化父组件再初始化子组件的方法(自定义父子组件mounted执行顺序)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是 Spring 新手,这就是我想要做的事情: 我正在使用一个基于 Maven 的库,它有自己的 Spring 上下文和 Autowiring 字段。 它的bean配置文件是src/test/res
我在我的测试脚本中有以下列表初始化: newSequenceCore=["ls", "ns", "*", "cm", "*", "ov", "ov", "ov", "ov", "kd"] (代表要在控
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Class construction with initial values 当我查看 http://en.
我得到了成员变量“objectCount”的限定错误。编译器还返回“ISO C++ 禁止非常量静态成员的类内初始化”。这是主类: #include #include "Tree.h" using n
我有如下所示的a.h class A { public: void doSomething()=0; }; 然后我有如下所示的b.h #include "a.h" class b: publi
我需要解析 Firebase DataSnapshot (一个 JSON 对象)转换成一个数据类,其属性包括 enum 和 list。所以我更喜欢通过传递 DataSnapshot 来手动解析它进入二
我使用 JQuery 一段时间了,我总是使用以下代码来初始化我的 javascript: $(document).ready( function() { // Initalisation logic
这里是 Objective-C 菜鸟。 为什么会这样: NSString *myString = [NSString alloc]; [myString initWithFormat:@"%f", s
我无法让核心数据支持的 NSArrayController 在我的代码中正常工作。下面是我的代码: pageArrayController = [[NSArrayController alloc] i
我对这一切都很陌生,并且无法将其安装到我的后端代码中。它去哪里?在我的页脚下面有我所有的 JS? 比如,这是什么意思: Popup initialization code should be exec
这可能是一个简单的问题,但是嘿,我是初学者。 所以我创建了一个程序来计算一些东西,它目前正在控制台中运行。我决定向其中添加一个用户界面,因此我使用 NetBeans IDE 中的内置功能创建了一个 J
我有 2 个 Controller ,TEST1Controller 和 TEST2Controller 在TEST2Controller中,我有一个initialize()函数设置属性值。 如果我尝
据我所知, dependentObservable 在声明时会进行计算。但如果某些值尚不存在怎么办? 例如: var viewModel ={}; var dependentObservable1 =
我正在阅读 POODR 这本书,它使用旧语法进行默认值初始化。我想用新语法实现相同的功能。 class Gear attr_reader :chainring, :cog, :wheel de
我按照 polymer 教程的说明进行操作: https://www.polymer-project.org/3.0/start/install-3-0 (我跳过了可选部分) 但是,在我执行命令“po
很抱歉问到一个非常新手的Kotlin问题,但是我正在努力理解与构造函数和初始化有关的一些东西。 我有这个类和构造函数: class TestCaseBuilder constructor(
假设我们有一个包含 30 列和 30 行的网格。 生命游戏规则简而言之: 一个小区有八个相邻小区 当一个细胞拥有三个存活的相邻细胞时,该细胞就会存活 如果一个细胞恰好有两个或三个活的相邻细胞,那么它就
我是 MQTT 和 Android 开放附件“AOA” 的新手。在阅读教程时,我意识到,在尝试写入 ByteArrayOutputStream 类型的变量之前,应该写入 0 或 0x00首先到该变量。
我有 2 个 Controller ,TEST1Controller 和 TEST2Controller 在TEST2Controller中,我有一个initialize()函数设置属性值。 如果我尝
我有一个inotify /内核问题。我正在使用“inotify” Python项目进行观察,但是,我的问题仍然是固有的关于inotify内核实现的核心。 Python inotify项目处理递归ino
我是一名优秀的程序员,十分优秀!