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
相关产品推荐
相关产品推荐

