如何通过编程方式渲染Vuejs 3中的组件?
我正在使用Vuejs 3。我正在尝试创建一个可以在整个应用程序中注入各种组件的对话框服务,然后用来打开对话框。例如:
使用构图API的理想状态:
rando_component.js
<template>
<div class="header-controls-layout">
<div class="left">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Media Library
</h2>
</div>
<div class="right">
<button @click="openUploadModal()">Upload</button>
</div>
</div>
</template>
<script setup>
import UploadMediaModal from '@/Components/UploadMediaModal.vue'
const dialogService = inject('dialog');// Inject dialog service
function updateTileSize(size){
this.tileSize = size;
}
function openUploadModal(){
//Open a dialog and pass a component to render with optional settings
dialogService.open(UploadMediaModal, {data: {}, width: '800px', height: '80vh'});
}
</script>
您会注意到,我正在注入键'对话框。在安装应用程序之前,我将在app.js中注册。
app.js
const vueapp = createApp();
VueSingleton.prototype.$vue = vueapp;
const instance = new DialogService("dialog-container");
vueapp.provide('dialog', instance);
vueapp.use(plugin);
vueapp.mixin({ methods: { route } });
vueapp.component('Dialog', Dialog);
vueapp.mount('#app');
dialog.service.js
import { VueSingleton } from "./singleton.vue";
import { ref, onUnmounted, createVNode, render } from 'vue';
export class DialogService extends VueSingleton {
_container = null;
_container_selector = '';
_modals = [];
constructor(selector){
super();
this._container_selector = selector;
}
open(component, {data, width, height, maxWidth, maxHeight}){
this._container = window.document.getElementById(this._container_selector);
let appContext = this.$vue._context.app._instance.appContext; // Seems wrong to me
let vnode = createVNode('Dialog', {component, data, width, height, maxWidth, maxHeight});
vnode.appContext = {...appContext };
render(vnode, this._container);
}
}
singleton.vue.js
export class VueSingleton{}
到目前为止,一切或多或少地工作。
在rando_component.js
上方的方法中启动openuploadmodal
方法,将对话框组件注入DOM。我可以在文档树检查器中看到对话框组件。
但是,这是问题开始的地方。如您所见,在上面的rando_component.js
中,我将一个组件(uploadMediamodal
)传递给OPEN方法。
这里的目标是,我想在对话框组件中渲染此组件(uploadMediamodal
)。,但是对话框组件并没有呈现其模板,甚至没有触发其生命周期挂钩。
为什么对话框组件渲染不?此外,如何通过编程方式渲染对话框组件中的另一个组件?
这是对话框组件: 对话框
<script setup>
import { ref, onUnmounted, getCurrentInstance,h, createVNode, render, onMounted } from 'vue';
const props = defineProps(["component", "data", "width", "max-width", "height", "max-height"]);
const container = ref();
const { appContext } = getCurrentInstance();
onMounted(() => {
// Not Firing
renderDialog();
})
// Destory Comp on unmount
onUnmounted(() => {
render(null, container);
});
function renderDialog(){
let vnode = createVNode(props.component, props.data || {});
vnode.appContext = {...appContext };
render(vnode, container);
}
</script>
<template>
<transition name="modal-fade">
<div class="modal-backdrop">
<div class="modal" role="dialog" aria-labelledby="modalTitle" aria-describedby="modalContent" :style="{'width': props.width || '600px', 'max-width': props.maxWidth || '100%', 'height': props.height || '400px', 'max-height': props.maxHeight || '80vh'}">
<!-- Modal Injecttion Container -->
<div ref="container" class="modal-body" id="modalContent"></div>
</div>
</div>
</transition>
</template>
<style>
.modal-backdrop {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
}
.modal {
background: #FFFFFF;
box-shadow: 2px 2px 20px 1px;
overflow-x: auto;
display: flex;
flex-direction: column;
}
.modal-body {
position: relative;
padding: 20px 10px;
}
.btn-close {
position: absolute;
top: 0;
right: 0;
border: none;
font-size: 20px;
padding: 10px;
cursor: pointer;
font-weight: bold;
color: #4AAE9B;
background: transparent;
}
.btn-green {
color: white;
background: #4AAE9B;
border: 1px solid #4AAE9B;
border-radius: 2px;
}
.modal-fade-enter,
.modal-fade-leave-to {
opacity: 0;
}
.modal-fade-enter-active,
.modal-fade-leave-active {
transition: opacity .5s ease;
}
</style>
<script setup>
</script>
<template>
<p>Upload Media Modal component working!</p>
</template>
<style lang="scss" scoped>
</style>
I'm using VueJS 3. I'm trying to create a dialog service that can be injected into various components throughout the application and then used to open a dialog. For example:
Ideal State using composition API:
random_component.js
<template>
<div class="header-controls-layout">
<div class="left">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Media Library
</h2>
</div>
<div class="right">
<button @click="openUploadModal()">Upload</button>
</div>
</div>
</template>
<script setup>
import UploadMediaModal from '@/Components/UploadMediaModal.vue'
const dialogService = inject('dialog');// Inject dialog service
function updateTileSize(size){
this.tileSize = size;
}
function openUploadModal(){
//Open a dialog and pass a component to render with optional settings
dialogService.open(UploadMediaModal, {data: {}, width: '800px', height: '80vh'});
}
</script>
As you'll notice, I'm injecting the key 'dialog'. I'm registering this in app.js just before mount the application.
app.js
const vueapp = createApp();
VueSingleton.prototype.$vue = vueapp;
const instance = new DialogService("dialog-container");
vueapp.provide('dialog', instance);
vueapp.use(plugin);
vueapp.mixin({ methods: { route } });
vueapp.component('Dialog', Dialog);
vueapp.mount('#app');
dialog.service.js
import { VueSingleton } from "./singleton.vue";
import { ref, onUnmounted, createVNode, render } from 'vue';
export class DialogService extends VueSingleton {
_container = null;
_container_selector = '';
_modals = [];
constructor(selector){
super();
this._container_selector = selector;
}
open(component, {data, width, height, maxWidth, maxHeight}){
this._container = window.document.getElementById(this._container_selector);
let appContext = this.$vue._context.app._instance.appContext; // Seems wrong to me
let vnode = createVNode('Dialog', {component, data, width, height, maxWidth, maxHeight});
vnode.appContext = {...appContext };
render(vnode, this._container);
}
}
singleton.vue.js
export class VueSingleton{}
Up until this point, everything works as expected more or less.
Firing the openUploadModal
method in method in the random_component.js
up above, injects the dialog component into the DOM. I can see the dialog component in the document tree inspector.
However this is where the problem begins. As you can see, in the random_component.js
above I'm passing a component(UploadMediaModal
) to the open method.
The goal here is that I would like to render this component(UploadMediaModal
) in the dialog component. But the Dialog component isn't rendering it's template or even firing it's lifecycle hooks.
Why isn't the dialog component rendering? Additionally, how do I programmatically render another component inside the dialog component?
Here is the dialog component:
Dialog.vue
<script setup>
import { ref, onUnmounted, getCurrentInstance,h, createVNode, render, onMounted } from 'vue';
const props = defineProps(["component", "data", "width", "max-width", "height", "max-height"]);
const container = ref();
const { appContext } = getCurrentInstance();
onMounted(() => {
// Not Firing
renderDialog();
})
// Destory Comp on unmount
onUnmounted(() => {
render(null, container);
});
function renderDialog(){
let vnode = createVNode(props.component, props.data || {});
vnode.appContext = {...appContext };
render(vnode, container);
}
</script>
<template>
<transition name="modal-fade">
<div class="modal-backdrop">
<div class="modal" role="dialog" aria-labelledby="modalTitle" aria-describedby="modalContent" :style="{'width': props.width || '600px', 'max-width': props.maxWidth || '100%', 'height': props.height || '400px', 'max-height': props.maxHeight || '80vh'}">
<!-- Modal Injecttion Container -->
<div ref="container" class="modal-body" id="modalContent"></div>
</div>
</div>
</transition>
</template>
<style>
.modal-backdrop {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
}
.modal {
background: #FFFFFF;
box-shadow: 2px 2px 20px 1px;
overflow-x: auto;
display: flex;
flex-direction: column;
}
.modal-body {
position: relative;
padding: 20px 10px;
}
.btn-close {
position: absolute;
top: 0;
right: 0;
border: none;
font-size: 20px;
padding: 10px;
cursor: pointer;
font-weight: bold;
color: #4AAE9B;
background: transparent;
}
.btn-green {
color: white;
background: #4AAE9B;
border: 1px solid #4AAE9B;
border-radius: 2px;
}
.modal-fade-enter,
.modal-fade-leave-to {
opacity: 0;
}
.modal-fade-enter-active,
.modal-fade-leave-active {
transition: opacity .5s ease;
}
</style>
UploadMediaModal.vue
<script setup>
</script>
<template>
<p>Upload Media Modal component working!</p>
</template>
<style lang="scss" scoped>
</style>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论