Vue3渲染函数:点击事件实现VNode子元素追加而非替换
解决Vue3动态追加VNode而非替换的问题
原代码中每次点击调用render(node, container.el)时,Vue的render函数会替换容器内的所有现有内容,这就是旧元素被覆盖的原因。以下是两种可行的解决方案:
方案一:利用响应式数组维护动态节点(推荐)
这种方式贴合Vue的响应式设计思路,通过响应式数组存储动态内容,每次点击向数组追加新项,渲染时自动生成包含所有历史项的VNode树:
import { defineComponent, h, ref } from "vue"; export default defineComponent({ setup() { // 响应式数组存储所有动态生成的文本内容 const dynamicItems = ref([]); const handleAdd = () => { dynamicItems.value.push(`Time: ${new Date().toISOString()}`); }; return () => { // 渲染容器时,包含按钮和所有动态生成的子节点 return h('div', [ h('button', { onClick: handleAdd }, ['Add New']), // 遍历数组生成对应的VNode ...dynamicItems.value.map(text => h('div', null, text)) ]); }; } })
方案二:手动指定render锚点实现追加
如果需要保留手动创建VNode并调用render的方式,可以通过render函数的第三个参数(锚点),将新节点插入到容器末尾,而非替换全部内容:
import { defineComponent, h, createVNode, render } from "vue"; export default defineComponent({ setup() { let containerEl = null; return () => { const container = h('div', { // 保存容器的DOM引用 ref: el => containerEl = el }); const button = h('button', { onClick: () => { const node = createVNode('div', null, [`Time: ${new Date().toISOString()}`]); node.appContext = container.appContext; // 第三个参数传null,将新节点插入到容器末尾(不会替换现有内容) render(node, containerEl, null); } }, ['Add New']) container.children?.push(button); return container; }; } })
说明
- 方案一无需手动操作DOM或VNode生命周期,依赖Vue的响应式自动更新,代码更简洁易维护,是优先推荐的方式。
- 方案二需要手动管理容器DOM引用和VNode的上下文,适合特定场景下需要精细控制节点挂载的情况。
内容的提问来源于stack exchange,提问作者alince
相关产品推荐
相关产品推荐

