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

如何将数据库取出的动态HTML包裹在Vue.js模板内容外部

问题场景

我需要将自定义HTML包裹在Vue模板内容外部,该需求无法通过<div v-html="HtmlWrapperTopHalf">插入内容实现,因为该指令会自动闭合未闭合的标签,而标签的闭合部分统一存放在动态HTML的下半部分,本质上我需要将Vue模板代码插入到动态模板HTML中。
我也无法提前预知动态HTML的内容并在Vue模板中构建对应结构:这些HTML来自用户通过富文本编辑器自主创建的内容,用户仅会在动态模板中间插入占位符{{MAIN_CONTENT}},此处即为Vue模板功能的渲染位置。

现有代码 Page.vue

<template>
    <div>
        //动态XHTML包裹层的上半部分放在此处
        <p>Inner Content Here</p>
        <ComponentA />
        <ComponentB />
        <!-- etc. --->
        <p>More Inner Content</p>
        //动态XHTML包裹层的下半部分放在此处
    </div>
</template>

<script>
    axios.get("getHtmlContent").then((result) =>{
       console.log("top", result.data.HtmlWrapperTopHalf)
       console.log("bottom", result.data.HtmlWrapperBottomHalf)
    });
</script>

接口返回示例

top: <div class="my-dynamic-class" id="my-unique-id"><h1>DYNAMIC TITLE</h1>
bottom: <div id="my-dynamic-footer">custom footer text</div></div>

期望输出效果

<div>
    <div class="my-dynamic-class" id="my-unique-id"><h1>DYNAMIC TITLE</h1>
    <p>Inner Content Here<p>
    <div>Hello from ComponentA!!</div>
    <div>Hello from ComponentB!!</div>
    <!-- etc. --->
    <p>More Inner Content<p>
    <div id="my-dynamic-footer">custom footer text</div></div>
</div>

概念示意图

概念示意图


解决方案

Vue3 推荐方案:Teleport 注入

不需要引入全量编译版本的Vue,不会破坏动态HTML标签结构,性能和安全性都更可控:

<template>
  <div>
    <!-- 渲染完整的动态HTML结构 -->
    <div v-html="fullDynamicHtml"></div>
    <!-- 内部内容通过Teleport注入到预留插槽 -->
    <Teleport to="#main-content-slot" v-if="slotReady">
      <p>Inner Content Here</p>
      <ComponentA />
      <ComponentB />
      <!-- 其余内部内容 -->
      <p>More Inner Content</p>
    </Teleport>
  </div>
</template>

<script setup>
import { ref, nextTick } from 'vue'
import axios from 'axios'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'

const fullDynamicHtml = ref('')
const slotReady = ref(false)

axios.get("getHtmlContent").then(async (result) => {
  const { HtmlWrapperTopHalf, HtmlWrapperBottomHalf } = result.data
  // 拼接完整动态HTML,把占位符替换为唯一标识的插槽节点
  fullDynamicHtml.value = `${HtmlWrapperTopHalf}<div id="main-content-slot"></div>${HtmlWrapperBottomHalf}`
  // 等待动态HTML渲染完成后再激活Teleport
  await nextTick()
  slotReady.value = true
})
</script>

Vue2 兼容方案:手动DOM挂载

Vue2没有原生Teleport,可通过手动创建组件实例挂载到预留插槽实现:

<template>
  <div>
    <div v-html="fullDynamicHtml"></div>
  </div>
</template>

<script>
import Vue from 'vue'
import axios from 'axios'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'

export default {
  components: { ComponentA, ComponentB },
  data() {
    return {
      fullDynamicHtml: ''
    }
  },
  async mounted() {
    const res = await axios.get("getHtmlContent")
    const { HtmlWrapperTopHalf, HtmlWrapperBottomHalf } = res.data
    this.fullDynamicHtml = `${HtmlWrapperTopHalf}<div id="main-content-slot"></div>${HtmlWrapperBottomHalf}`
    await this.$nextTick()
    // 创建内部内容组件实例
    const InnerContent = Vue.extend({
      template: `
        <div>
          <p>Inner Content Here</p>
          <ComponentA />
          <ComponentB />
          <p>More Inner Content</p>
        </div>
      `,
      components: { ComponentA, ComponentB }
    })
    const innerInstance = new InnerContent().$mount()
    // 插入到预留插槽位置
    document.querySelector('#main-content-slot').appendChild(innerInstance.$el)
  }
}
</script>

安全提示:用户自主输入的富文本HTML存在XSS注入风险,建议在渲染前对动态HTML内容做过滤处理,剔除恶意脚本和危险标签。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 20:06:05