Vue插槽渲染对象内HTML字符串失效,不使用v-html如何解决?
你当前使用双大括号{{ }}插值时,Vue默认会对内容做HTML转义,核心目的就是防止XSS攻击,所以所有HTML标签都会被当成普通字符串渲染。
要渲染HTML结构必然需要用到解析HTML的能力,你不想直接用v-html本质是怕不可信内容带来的XSS风险,所以正确的做法是先对CMS返回的HTML内容做XSS安全过滤,再通过v-html渲染,这也是目前业界的通用方案,不存在完全规避v-html还能解析HTML的原生Vue能力。
方案1:使用成熟的XSS过滤库处理后再渲染(推荐)
最常用的是DOMPurify,它会自动清理HTML字符串中的所有危险代码,只保留安全的标签和属性,使用方式:
- 安装依赖
npm install dompurify # 或者 yarn add dompurify
- 在组件中使用
<template #content> <div v-html="sanitizedContent(item.content)"></div> </template> <script setup> import DOMPurify from 'dompurify' const sanitizedContent = (content) => { return DOMPurify.sanitize(content) } </script>
这个方案经过大量生产场景验证,安全性有保障,开发成本极低。
方案2:自定义白名单过滤(适合轻量场景)
如果你的场景只需要支持非常有限的HTML标签(比如仅允许<p>、<h2>、<ul>、<li>、<strong>这些基础标签),不想引入第三方依赖,可以自己实现一个简单的白名单过滤函数:
// 允许的标签白名单 const allowedTags = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'strong', 'em', 'span'] // 允许的属性白名单 const allowedAttrs = ['class', 'style', 'href'] const sanitizeHtml = (html) => { // 简单实现,复杂场景还是推荐用DOMPurify return html.replace(/<(\/?)(\w+)([^>]*?)>/g, (match, closeTag, tag, attrs) => { tag = tag.toLowerCase() if (!allowedTags.includes(tag)) return '' // 过滤属性 const safeAttrs = attrs.replace(/(\w+)\s*=\s*"([^"]*)"/g, (attrMatch, attrName, attrValue) => { attrName = attrName.toLowerCase() if (!allowedAttrs.includes(attrName)) return '' // 额外处理href的javascript:伪协议风险 if (attrName === 'href' && attrValue.trim().startsWith('javascript:')) return '' return `${attrName}="${attrValue}"` }) return `<${closeTag}${tag}${safeAttrs}>` }) }
过滤后的内容同样可以通过v-html安全渲染。
方案3:手动解析HTML生成VNode(适合自定义渲染场景)
如果你需要对HTML的渲染做更细粒度的控制(比如把<a>标签自动转换成Vue Router的<RouterLink>组件),可以使用HTML解析库把HTML字符串解析成AST,再通过Vue的h()渲染函数生成虚拟节点插入插槽,这种方案完全不需要用到v-html,但开发成本较高,适合复杂定制需求。
内容的提问来源于stack exchange,提问作者Udders
相关产品推荐
相关产品推荐

