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

Vue3初始化后插入原始HTML组件标签如何触发渲染

Vue3 遗留项目动态插入HTML自动渲染全局组件方案

核心背景

  • 项目已初始化完成注册全局组件的Vue3实例,原有业务逻辑依赖jsrender,在AJAX请求返回数据后渲染HTML字符串插入#app容器内部
  • Vue初始化完成后动态插入的原始HTML中,自定义组件标签(如<my-vue-component>)不会被Vue自动识别编译
  • 需求为无需一次性全量迁移jsrender模板逻辑,支持渐进式引入Vue3组件,让动态插入的组件标签可以像初始挂载阶段一样正常渲染

实现原理

Vue3未提供全局重新扫描全页DOM的API,但可以针对jsrender每次渲染插入的DOM块做局部编译挂载,完全不影响原有jsrender渲染的静态内容,无侵入性。

具体实现

1. 封装局部DOM编译工具方法

import { createApp, h } from 'vue'
// 引入项目主入口已经初始化完成、注册完全局组件/插件的Vue实例
import mainApp from '@/main'

/**
 * 扫描指定容器内的未渲染Vue组件标签,完成挂载
 * @param {HTMLElement} container jsrender渲染内容的父容器
 */
function mountVueComponentsIn(container) {
  // 跳过已经被Vue接管的节点,避免重复渲染
  if (container.__vueParentComponent) return

  // 获取主应用注册的所有全局组件名,做标签匹配
  const globalComponents = mainApp._context.components
  const validComponentTags = new Set(
    Object.keys(globalComponents).map(tagName => tagName.toLowerCase())
  )

  // 筛选出容器内所有未挂载的组件节点
  const pendingMountNodes = Array.from(container.querySelectorAll('*')).filter(node => {
    const currentTag = node.tagName.toLowerCase()
    return validComponentTags.has(currentTag) && !node.__vueParentComponent
  })

  pendingMountNodes.forEach(node => {
    // 为每个独立组件创建轻量挂载实例,完全继承主应用的全局配置
    const renderApp = createApp({
      render() {
        const targetComponent = globalComponents[node.tagName.toLowerCase()]
        // 透传DOM上写的所有属性作为组件props
        const props = {}
        Array.from(node.attributes).forEach(attr => {
          props[attr.name] = attr.value
        })
        // 保留组件标签内jsrender渲染的原有内容,作为默认插槽传入
        const slots = {
          default: () => h('div', { innerHTML: node.innerHTML })
        }
        return h(targetComponent, props, slots)
      }
    })

    // 同步主应用的全局配置、指令、插件、依赖注入内容,保证组件运行环境和主应用一致
    renderApp.config.globalProperties = mainApp.config.globalProperties
    renderApp._context.components = globalComponents
    renderApp._context.directives = mainApp._context.directives
    renderApp._context.provides = mainApp._context.provides

    // 挂载到对应DOM节点,替换原有占位标签
    renderApp.mount(node)
  })
}

2. 对接原有jsrender渲染流程

只需要在每次jsrender渲染完成、HTML插入DOM之后,调用一次上面的工具方法即可,不需要修改任何原有jsrender模板代码:

// 原有AJAX+jsrender逻辑示例
$.get('/api/biz/data', (res) => {
  const renderTmpl = $.templates('#some-name-tmpl')
  const renderHtml = renderTmpl.render(res.data)
  const contentContainer = document.querySelector('#jsrender-content-area')
  // 原有插入逻辑
  contentContainer.innerHTML = renderHtml
  // 新增一行:扫描刚插入的内容,自动挂载Vue组件
  mountVueComponentsIn(contentContainer)
})

注意事项

  • 性能开销极低:方法只会匹配注册过的全局组件标签,不会重渲染已经被Vue接管的节点,也不会改动jsrender输出的静态DOM结构
  • 混合渲染兼容:jsrender渲染在组件标签内部的静态内容会自动作为默认插槽传入Vue组件,原生DOM绑定的事件不受影响
  • 模板写法无改动:jsrender模板里直接写全局注册的Vue组件标签即可,和普通HTML标签用法完全一致,不需要额外标记

内容的提问来源于stack exchange,提问作者s0up

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:18:19