Appearance
v-safe-html
一个安全的 HTML 渲染指令,支持 Markdown 转换和 XSS 防护。
功能特性
- 支持 Markdown 语法转换为 HTML
- 自动清理潜在的 XSS 攻击内容
- 支持常见的 Markdown 格式(标题、列表、加粗等)
- 异步处理,确保性能
- 支持自定义 DOMPurify 配置
- 支持动态内容更新
安全配置
默认的安全配置包括:
- 允许
data-*
属性 - 允许未知协议(如
tel:
、mailto:
) - 禁止
script
标签 - 禁止危险的事件属性(如
onclick
、onerror
、onload
)
你可以通过修改 getDOMPurifyConfig
函数来自定义安全配置:
typescript
function getDOMPurifyConfig() {
return {
ALLOW_DATA_ATTR: true,
ALLOW_UNKNOWN_PROTOCOLS: true,
FORBID_TAGS: ['script'],
FORBID_ATTR: ['onclick', 'onerror', 'onload'],
// 添加更多配置...
}
}
使用示例
基础用法
vue
<template>
<div v-safe-html="markdownContent"></div>
</template>
<script setup>
const markdownContent = `
# 标题
这是一段**加粗**的文本
## 子标题
- 列表项 1
- 列表项 2
[链接文本](https://example.com)
\`\`\`javascript
console.log('代码块');
\`\`\`
`
</script>
动态内容
vue
<template>
<div v-safe-html="content"></div>
<button @click="updateContent">更新内容</button>
</template>
<script setup>
import { ref } from 'vue'
const content = ref('# 初始内容')
function updateContent() {
content.value = `
# 更新后的内容
- 新的列表项
- 另一个列表项
`
}
</script>
条件渲染
vue
<template>
<div v-if="hasContent" v-safe-html="content"></div>
<div v-else>暂无内容</div>
</template>
<script setup>
import { computed } from 'vue'
const content = ref('')
const hasContent = computed(() => content.value.trim().length > 0)
</script>
支持的 Markdown 语法
- 标题(# 到 ######)
- 加粗(文本)
- 斜体(文本)
- 列表(有序和无序)
- 链接
- 图片
- 代码块
- 引用
- 表格
- 等等
性能优化建议
- 对于静态内容,建议在组件挂载时只转换一次
- 对于动态内容,可以使用
v-once
指令避免重复转换 - 大量内容建议使用虚拟滚动或分页加载
注意事项
- 指令是异步的,内容会在转换完成后显示
- 如果输入为
null
或undefined
,将清空元素内容 - 如果转换过程中发生错误,将显示空内容并在控制台输出错误信息
- 确保输入的内容是字符串类型
- 注意内存使用,避免过大的 Markdown 内容
错误处理
如果发生错误,指令会:
- 在控制台输出错误信息
- 清空元素内容
- 确保不会渲染不安全的 HTML
常见错误及解决方案:
- 类型错误:确保传入的内容是字符串类型
- 转换错误:检查 Markdown 语法是否正确
- 内存错误:考虑分块处理大内容
最佳实践
1. 内容验证
typescript
function validateContent(content: string): boolean {
return typeof content === 'string' && content.trim().length > 0
}
2. 错误边界处理
vue
<template>
<div v-safe-html="content" @error="handleError"></div>
</template>
<script setup>
function handleError(error: Error) {
console.error('Content processing error:', error)
// 实现自定义错误处理逻辑
}
</script>
3. 加载状态处理
vue
<template>
<div v-if="isLoading">加载中...</div>
<div v-else v-safe-html="content"></div>
</template>
<script setup>
const isLoading = ref(true)
const content = ref('')
onMounted(async () => {
try {
// 加载内容
content.value = await fetchContent()
} finally {
isLoading.value = false
}
})
</script>