vue实现portal
Vue 实现 Portal 功能
Portal(传送门)是一种将子节点渲染到父组件 DOM 结构之外的 DOM 节点中的技术,常用于模态框、弹出菜单、通知等场景。Vue 本身不直接提供 Portal 功能,但可以通过以下方式实现。
使用 Vue 3 的 Teleport 组件
Vue 3 内置了 Teleport 组件,可以轻松实现 Portal 功能。以下是一个示例:

<template>
<button @click="showModal = true">打开模态框</button>
<Teleport to="body">
<div v-if="showModal" class="modal">
<p>这是一个模态框</p>
<button @click="showModal = false">关闭</button>
</div>
</Teleport>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const showModal = ref(false);
return { showModal };
}
};
</script>
<style>
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border: 1px solid #ccc;
}
</style>
使用 Vue 2 的第三方库
Vue 2 可以通过第三方库如 portal-vue 实现 Portal 功能。安装并引入 portal-vue:

npm install portal-vue
在 Vue 2 项目中使用:
<template>
<button @click="showModal = true">打开模态框</button>
<portal to="body">
<div v-if="showModal" class="modal">
<p>这是一个模态框</p>
<button @click="showModal = false">关闭</button>
</div>
</portal>
</template>
<script>
export default {
data() {
return {
showModal: false
};
}
};
</script>
<style>
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border: 1px solid #ccc;
}
</style>
手动实现 Portal
如果不想依赖第三方库,可以手动实现 Portal。以下是一个简单的实现方式:
<template>
<button @click="showModal = true">打开模态框</button>
</template>
<script>
export default {
data() {
return {
showModal: false
};
},
watch: {
showModal(newVal) {
if (newVal) {
this.createPortal();
} else {
this.removePortal();
}
}
},
methods: {
createPortal() {
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<p>这是一个模态框</p>
<button id="close-modal">关闭</button>
`;
document.body.appendChild(modal);
document.getElementById('close-modal').addEventListener('click', () => {
this.showModal = false;
});
},
removePortal() {
const modal = document.querySelector('.modal');
if (modal) {
document.body.removeChild(modal);
}
}
},
beforeDestroy() {
this.removePortal();
}
};
</script>
<style>
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border: 1px solid #ccc;
}
</style>
注意事项
- 使用
Teleport或portal-vue时,确保目标 DOM 节点存在,否则会报错。 - 手动实现 Portal 时,注意清理事件监听器和 DOM 节点,避免内存泄漏。
- Portal 的目标节点可以是任何有效的 DOM 节点,如
body、#app或其他自定义节点。






