vue.js - 在全局应用组件中渲染一个子组件
问题描述
我编写了一个对话框组件(全局)来显示带有叠加层的模态对话框,如弹出表单。
现在,对话框在使用它的组件内呈现。如果之后在 html 代码中存在相对位置的内容,这会导致内容重叠。
我希望它在最后呈现在根 App 组件中,以便我可以强制对话框始终位于所有其他内容之上。
这是我不工作的解决方案:我尝试使用命名槽,希望它们也能在组件树中向后工作。不幸的是,他们似乎没有这样做。
任何人的解决方案如何做到这一点?
我的下一个想法是使用存储在应用程序组件中的额外组件进行渲染,并在全局状态中注册对话框。但是这个解决方案会非常复杂,看起来有点脏。
对话框组件:
<template v-slot:dialogs>
<div class="dialog" :class="{'dialog--open': show, 'dialog--fullscreen': fullscreen }">
<transition name="dialogfade" duration="300">
<div class="dialog__overlay" v-if="show && !fullscreen" :key="'overlay'" @click="close"></div>
</transition>
<transition name="dialogzoom" duration="300">
<div class="dialog__content" :style="{'max-width': maxWidth}" v-if="show" :key="'content'">
<slot></slot>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "MyDialog",
props: {show: {
type: Boolean,
default: false
},
persistent: {
type: Boolean,
default: true
},
fullscreen: {
type: Boolean,
default: false
},
maxWidth: {
type: String,
default: '600px'
}
},
data: () => ({}),
methods: {
close() {
if(!this.persistent) {
this.$emit('close')
}
}
}
}
</script>
应用组件的模板:
<template>
<div class="application">
<div class="background">
<div class="satellite"></div>
<div class="car car-lr" :style="{ transform: `translateY(${car.x}px)`, left: adjustedLRLeft + '%' }" v-for="car in carsLR"></div>
</div>
<div class="content">
<login v-if="!$store.state.user"/>
<template v-else>
<main-menu :show-menu="showMainMenu" @close="showMainMenu = false"/>
<router-view/>
</template>
<notifications/>
<div class="dialogs"><slot name="dialogs"></slot></div>
</div>
</div>
</template>
解决方案
在vuetify2 项目的帮助下,我找到了解决方案。对话框组件获得一个ref="dialogContent"属性,魔术发生在beforeMount函数中。
<template>
<div class="dialog" ref="dialogContent" :class="{'dialog--open': show, 'dialog--fullscreen': fullscreen }">
<transition name="dialogfade" duration="300">
<div class="dialog__overlay" v-if="show && !fullscreen" :key="'overlay'" @click="close"></div>
</transition>
<transition name="dialogzoom" duration="300">
<div class="dialog__content" :style="{'max-width': maxWidth}" v-if="show" :key="'content'">
<slot></slot>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "MyDialog",
props: {
show: {
type: Boolean,
default: false
},
persistent: {
type: Boolean,
default: true
},
fullscreen: {
type: Boolean,
default: false
},
maxWidth: {
type: String,
default: '600px'
}
},
data: () => ({}),
methods: {
close() {
if (!this.persistent) {
this.$emit('close')
}
}
},
beforeMount() {
this.$nextTick(() => {
const target = document.getElementById('dialogs');
target.appendChild(
this.$refs.dialogContent
)
})
},
}
</script>
推荐阅读
- ios - 如何解决嵌套 StackView 的布局问题?
- python - 将 JSON 数据过滤到 CSV 列表中
- sql - SQL 输出文件包含空值,但我在选择语句中使用 isnull
- vue.js - 在表单 POST 方法中使用 Cordova InAppBrowser
- c# - ASP.NET 核心任务
没有异步就无法返回 NotFound() 和 OK() - json - 在json数据中动态搜索
- sql - Oracle APEX:将主键分配为交互式网格 ROWID,在 SQL 查询中使用选择交互式网格 ROWID
- sql - 创建一个用其他表的记录计数填充的表
- pandas - 从某些固定分区中的日期时间对象创建值
- spring-boot - Nullpointer Exception 未知资源 springmicriservice