Vue 3组合式函数动态挂载组件需用createVNode+render手动创建并渲染虚拟节点到DOM容器,再插入页面,同时提供卸载方法;事件需通过props传入,不继承父上下文。

在 Vue 3 的组合式函数(Composable)中动态挂载组件,核心是利用 createApp + createVNode + render 三者协作,而非依赖模板中的 <component :is></component>。这种方式适合弹窗、提示框、临时浮层等“非声明式、运行时创建”的场景。
关键步骤:手动创建并挂载到真实 DOM
组合式函数中不直接操作 app.mount()(那是根实例用的),而是通过虚拟节点渲染到一个新创建或指定的 DOM 容器:
- 用
createVNode将组件构造器转为虚拟节点(支持 props、事件、插槽) - 用
render把该 vnode 渲染进一个真实 DOM 元素(如document.createElement('div')) - 将该 DOM 元素插入页面(如
document.body.appendChild(el)) - 返回卸载方法:调用
render(null, el)清空,并移除 DOM 节点
典型实现:封装一个可复用的挂载函数
以下是一个标准的组合式函数示例(TypeScript 友好):
import { createVNode, render, getCurrentInstance } from 'vue'
import type { Component, VNode, App } from 'vue'
export function useMountComponent<T extends Component>(
component: T,
props?: Record<string, any>,
children?: any
) {
const container = document.createElement('div')
let vnode: VNode | null = null
const mount = () => {
vnode = createVNode(component, props, children)
render(vnode, container)
document.body.appendChild(container)
}
const unmount = () => {
if (vnode && container.parentNode) {
render(null, container)
container.remove()
vnode = null
}
}
return { mount, unmount }
}
</font>
<p>使用时只需传入组件、配置项即可:</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill11726" title="Springboot Vue Builder"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20e352aa140.jpg" alt="Springboot Vue Builder" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill11726" title="Springboot Vue Builder">Springboot Vue Builder</a>
<p>从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。</p>
</div>
<a href="/xiazai/skill11726" title="Springboot Vue Builder" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>
<font color="#888">
<pre class="brush:php;toolbar:false;">
// 在 setup 或 composable 中
const { mount, unmount } = useMountComponent(ConfirmModal, {
title: '确认删除?',
onConfirm: () => console.log('已确认'),
onClose: unmount
})
mount()
注意事项:事件与响应式需显式桥接
动态挂载的组件无法自动继承父组件上下文(如 getCurrentInstance() 为 null),所以:
- 事件回调必须由外部传入 props(如
onConfirm),不能依赖emit后再由父级监听 - 若需访问全局属性(如
$message),需提前通过app.config.globalProperties注册,并在挂载前手动注入上下文(较复杂,一般推荐传函数) - 避免多次重复挂载同一组件实例;每次调用应新建 vnode 和容器
替代方案:配合 defineAsyncComponent 懒加载
如果目标是“按需加载+动态切换”,而非“完全运行时创建”,更轻量的做法是结合 defineAsyncComponent 和 <component :is></component>:
- 用
defineAsyncComponent(() => import('./Modal.vue'))包裹异步组件 - 在模板中用
<component :is="modalComp" v-bind="props"></component> - 在组合式函数中控制
modalComp的赋值与清空(即“逻辑挂载”,非真实 DOM 挂载)
这种方式无需手动管理 DOM,也天然支持 <keep-alive></keep-alive> 和响应式更新,适合 tab 切换、路由级动态组件等场景。

















