在实际的前端开发中,使用 Vue 的 v-html 指令来渲染来自后端的 HTML 字符串时,遇到一个常见现象:EM 标签(通常指 强调文本 的标签)似乎无法被正确解析。本文将从原理出发,剖析可能的原因,并给出若干 实战解决方案,帮助你在不牺牲性能和安全性的前提下正确渲染包含 EM 标签的内容。
2-1. v-html 的工作原理与局限
2-1.1 v-html 的核心机制
v-html 实质上只是把一个字符串写入到 DOM 的 innerHTML 属性中,作为一个普通的 HTML 片段进行浏览器渲染。这意味着它并不会对字符串中的模板语法进行解析,也不会执行 Vue 的指令、组件或生命周期逻辑。它的渲染结果取决于浏览器对 HTML 的原生解析能力,而不是 Vue 的模板编译过程。
在上面的例子中,字符串中的 HTML 实体需要被正确还原为真实标签,才能让 EM 标签生效,后续的渲染才会包含强调文本。
2-1.2 EM 标签在字符串中的表现与边界
从浏览器的角度来看, 作为一个内联标签,是完全符合 HTML 标准的,应该能够被正确解析并呈现为强调文本。问题并不来自标签本身,而往往来自数据传输、编码、或前后端协作的过程中的其他环节:
export default {data() {return {// 直接包含实际标签htmlContent: '这是一个 强调 文本。
'}}
}
2-2. 常见导致 v-html 无法解析 EM 标签的原因
2-2.1 数据源对标签进行了 HTML 实体转义
如果后端返回的是经过转义的 HTML 字符串,例如 <p>这是一个 <em>强调</em>文本</p></p>,那么在前端直接把该字符串通过 v-html 渲染时,浏览器会把它当作普通文本处理,而不是 HTML 标签。因此 EM 标签不会被解析成实际的标签,页面只会显示转义后的文本内容。
// 后端返回示例
const escapedHtml = '<p>这是一个 <em>强调</em>文本</p>';
// v-html 渲染后,页面会显示转义字符,而不是真正的标签
解决思路:在客户端对数据进行适当的解码,或在服务端确保发送的是未转义的 HTML 字符串,并在使用时明确告知数据源的可信度。
2-2.2 v-html 与模板编译的边界
请注意,v-html 的内容不会经过 Vue 的模板编译,这意味着在 v-html 的 HTML 字符串中如果包含 Vue 指令、绑定语法或组件标记,它们不会被解析或执行。EM 标签如果只是普通的 HTML 标签则会被浏览器渲染,但如果你在字符串中混入了如 v-if、v-bind 等 Vue 指令,它们将以文本形式出现,既不会执行也不会触发响应式。
// 这段 HTML 将不会被 Vue 编译执行
const dangerousHtml = '<div v-if="show">条件渲染</div>';
2-3. 实战解决方案:让 EM 标签正确被解析且保持安全
2-3.1 确认字符串未被转义
在继续之前,确保数据源返回的是未转义的 HTML 字符串,而不是经过实体编码的文本。如果数据源已经转义,需要在渲染前先解码,否则浏览器只会把它当成文本,而不是 HTML 片段。

// 示例:本地解码(仅信任源时使用)
// 将转义的标签还原为实际标签
function decodeHtml(html) {const txt = document.createElement('textarea');txt.innerHTML = html;return txt.value;
}// 使用示例
export default {data() {return {rawHtml: '<p>这是一个 <em>强调</em> 文本</p>'}},computed: {decodedHtml() {return decodeHtml(this.rawHtml);}}
}
2-3.2 使用 DOMPurify 等净化工具进行有选择的保留
为了解决潜在的 XSS 风险,同时保留 EM 标签 等安全标签,可以在渲染前对 HTML 进行净化。通过配置允许标签集合,可以在确保安全的前提下保留 EM 标签。
// 使用 DOMPurify 进行净化,保留 标签
import DOMPurify from 'dompurify';export default {data() {return {htmlRaw: '这是 强调 的文本
'}},computed: {safeHtml() {return DOMPurify.sanitize(this.htmlRaw, { ALLOWED_TAGS: ['p', 'em'] });}}
}
2-3.3 服务端与前端都要做好编码一致性
为避免编码错配,在前后端协作时应明确约定:服务器传输的 HTML 字符串应是已就位的 HTML 片段,不应在中间阶段被不必要地转义。另外,在跨域或 SSR 场景下,确保中间件或插件链路没有对 HTML 进行二次转义。
// 服务器端(示例伪代码)
// 假设后端直接输出未转义的片段
const htmlFragment = '这是 强调 的文本
';
response.setHeader('Content-Type', 'text/html; charset=utf-8');
response.end(htmlFragment);
2-3.4 在模板中避免将 Vue 指令嵌入到 v-html 的内容
如果你确实需要让某些指令起作用,应该把相关逻辑放到 Vue 模板中管理,而不是放在 v-html 渲染的字符串中。把动态行为绑定在可编译的模板上,以确保可维护性与性能。

