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

如何将服务端渲染的原生DOM元素传入Vue应用并在插槽中渲染

解决方案

核心思路是直接提取挂载容器的原有原生DOM节点引用,通过渲染函数传入目标组件插槽,全程不涉及HTML字符串解析,完全规避XSS风险。

Vue 2 实现步骤

  1. 提前提取挂载容器的原有子节点,避免挂载时被直接覆盖丢失
const mountContainer = document.querySelector('.c-search')
// 转成数组存储原始DOM节点引用
const originalChildNodes = Array.from(mountContainer.childNodes)
  1. 挂载时通过渲染函数的子节点参数,将DOM节点传入组件默认插槽
new Vue({
  render: (h) => h(NameOfTheComponent, null, originalChildNodes)
}).$mount(mountContainer)
  1. 在NameOfTheComponent组件模板对应位置添加默认插槽即可渲染原有内容
<!-- NameOfTheComponent 组件内 -->
<template>
  <div class="search-wrapper">
    <!-- 其他组件内容 -->
    <slot /> <!-- 原有服务端渲染的DOM会直接渲染在这里 -->
  </div>
</template>

具名插槽适配

如果需要将不同节点分配到对应具名插槽,可以提前对原有节点做分类:

const slots = {
  default: [],
  disclaimer: []
}
originalChildNodes.forEach(node => {
  // 匹配指定类名的节点放入disclaimer插槽
  if (node.nodeType === 1 && node.classList.contains('c-search__disclaimer')) {
    slots.disclaimer.push(node)
  } else {
    slots.default.push(node)
  }
})

new Vue({
  render: (h) => h(NameOfTheComponent, {
    scopedSlots: {
      default: () => slots.default,
      disclaimer: () => slots.disclaimer
    }
  })
}).$mount(mountContainer)

组件内直接使用对应具名插槽即可:

<slot name="disclaimer" />

Vue 3 实现步骤

逻辑和Vue2一致,仅API写法不同:

import { createApp, h } from 'vue'
const mountContainer = document.querySelector('.c-search')
const originalChildNodes = Array.from(mountContainer.childNodes)

createApp({
  render: () => h(NameOfTheComponent, null, {
    default: () => originalChildNodes
  })
}).mount(mountContainer)

方案优势

  • 全程不使用v-html,没有HTML字符串解析环节,完全规避XSS安全风险,符合Vue官方安全规范
  • 原有DOM节点的所有属性、原生事件绑定都会完整保留,不需要额外做属性同步
  • 浏览器不会重复执行原有DOM内的script标签,即使CMS内容被植入恶意脚本也不会触发执行,安全性更高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 05:45:00