You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 01:05:25