Vue3使用h函数和render函数动态插入组件和元素

文章介绍了在Vue中如何利用h函数创建虚拟DOM节点,并通过render函数将其动态挂载到指定的DOM位置,以实现组件的动态渲染。在父组件中,于onMounted生命周期钩子内创建了一个容器,然后将Test组件渲染并插入到.home-box的第一个子元素之前。

首先明白两个函数的大致作用

  1. h函数(createVnode)用于创建一个虚拟DOM(用法可以自行查看文档);
  2. render函数用于输出虚拟DOM;在Vue是无法使用原生的方式将组件当做普通DOM动态加入到其他的DOM中,通过render函数的第二个参数指定需要挂载DOM

父组件代码片

// An highlighted block
<template>
	<div class="home-box"></div>
</emplate>


<script setup>
import { ref, h,render,onMounted} from 'vue'
import Test from './Test.vue'
onMounted(() => {
		//创建一个容器用于存放需要动态渲染的组件
		let son = document.createElement('div')
		//把容器插入到指定的位置
		document
			.querySelector('.home-box')
			.insertBefore(son,document.querySelector('.home-box').firstChild)
		//使用render函数把组件挂载到容器上
		//第一个参数是我们使用h函数创造的VNode
		//第二个参数是需要挂载的位置
		render(h(Test),son)
	})

Test组件内容

 <template>
	<el-button>{{ 0 }}</el-button>
	<el-button>{{ 0 }}</el-button>
</template>

最后的效果
在这里插入图片描述

### 函数式 Message 组件封装原理 在 Vue 3 中,可以通过 `h` `render` 函数实现一个函数式的 `Message` 弹窗组件。该方式允许开发者像调用普通 JavaScript 函数一样使用组件,例如 `message.success(&#39;提示内容&#39;)` 或者 `message({ type: &#39;success&#39;, msg: &#39;提示内容&#39; })`。 #### 实现思路 - 使用 `defineComponent` 定义基础的 `Message` 组件。 - 利用 `h` 创建虚拟节点(VNode)。 - 使用 `render` 方法将组件动态渲染到 DOM 中。 - 将不同类型的提示方法挂载为对象属性,支持链式调用对象传参形式 [^1]。 --- ### 核心代码实现 #### Message.vue(基础组件) ```vue <template> <transition name="fade"> <div :class="[&#39;app-message&#39;, &#39;app-message--&#39; + type]" v-show="visible" :style="{ top: offset + &#39;px&#39; }"> <span>{{ msg }}</span> <span class="close-btn" @click="close" v-if="showClose">×</span> </div> </transition> </template> <script setup> import { ref, onMounted } from &#39;vue&#39; const props = defineProps({ type: { type: String, default: &#39;info&#39;, validator: (value) => [&#39;info&#39;, &#39;success&#39;, &#39;warning&#39;, &#39;error&#39;].includes(value) }, msg: { type: String, required: true }, duration: { type: Number, default: 3000 }, offset: { type: Number, default: 20 }, showClose: { type: Boolean, default: false } }) const visible = ref(true) const close = () => { visible.value = false } onMounted(() => { if (duration > 0) { setTimeout(() => { close() }, duration) } }) </script> ``` --- #### messageBox.ts(函数式封装逻辑) ```ts import { h, render, defineComponent } from &#39;vue&#39; import Message from &#39;./Message.vue&#39; type MessageType = &#39;info&#39; | &#39;success&#39; | &#39;warning&#39; | &#39;error&#39; interface MessageOptions { type?: MessageType msg: string duration?: number offset?: number showClose?: boolean } const container = document.createElement(&#39;div&#39;) document.body.appendChild(container) function createMessage(options: MessageOptions) { const props = { type: options.type || &#39;info&#39;, msg: options.msg, duration: options.duration ?? 3000, offset: options.offset ?? 20, showClose: options.showClose ?? false } const VNode = h(Message, props) render(VNode, container) } // 挂载类型方法 const message = Object.assign(createMessage, { info(msg: string, duration?: number, options: Partial<MessageOptions> = {}) { createMessage({ type: &#39;info&#39;, msg, duration, ...options }) }, success(msg: string, duration?: number, options: Partial<MessageOptions> = {}) { createMessage({ type: &#39;success&#39;, msg, duration, ...options }) }, warning(msg: string, duration?: number, options: Partial<MessageOptions> = {}) { createMessage({ type: &#39;warning&#39;, msg, duration, ...options }) }, error(msg: string, duration?: number, options: Partial<MessageOptions> = {}) { createMessage({ type: &#39;error&#39;, msg, duration, ...options }) } }) export default message ``` --- #### 全局注册与使用 ##### main.js ```ts import message from &#39;@/components/Message&#39; const app = createApp(App) app.config.globalProperties.$message = message app.mount(&#39;#app&#39;) ``` ##### 在组件使用 ```ts import message from &#39;@/components/Message&#39; message.success(&#39;操作成功!&#39;) message({ type: &#39;error&#39;, msg: &#39;网络错误,请重试&#39;, duration: 2000, showClose: true }) ``` --- ### 特性说明 - 支持通过 `.success()`、`.info()` 等语法调用。 - 支持通过对象传参方式调用 `message({ type: &#39;success&#39;, msg: &#39;...&#39; })` [^1]。 - 可配置 `duration` 控制显示时长、`offset` 设置偏移位置、`showClose` 显示关闭按钮 [^2]。 - 支持全局挂载或局部导入使用。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值