Vue.js如何自动转义插槽内HTML代码适配highlight.js高亮?
解决Vue插槽中HTML代码自动转义并高亮的问题
嘿,我完全懂你现在的困扰——你做的这个highlight.js代码高亮组件,插槽里塞HTML代码的时候直接被渲染成页面元素了,手动转义<和>虽然能用,但每次都这么搞太麻烦了对吧?别担心,我给你几个靠谱的自动转义方案:
方案一:通过作用域插槽获取原始内容并自动转义
这是最灵活的方案,适合绝大多数场景,不管插槽里是静态还是动态内容都能处理。核心思路是在组件内部获取插槽的原始内容,转义后再传给highlight.js高亮:
组件代码改造
<script setup> import hljs from 'highlight.js' import 'highlight.js/styles/github.css' // 选你喜欢的高亮样式 const props = defineProps({ language: { type: String, default: 'html' // 默认高亮HTML } }) // 核心:HTML字符转义工具函数,覆盖所有特殊字符 const escapeHtml = (str) => { return str .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, ''') } // 获取插槽的原始内容并转义 const getEscapedSlotContent = () => { const slots = useSlots() if (!slots.default) return '' let rawContent = '' // 遍历插槽的所有vnode,提取原始文本/HTML slots.default().forEach(vnode => { if (vnode.type === Text) { rawContent += vnode.children } else if (vnode.el) { rawContent += vnode.el.innerHTML } }) return escapeHtml(rawContent) } // 组件挂载后初始化highlight.js高亮 onMounted(() => { const codeElement = document.querySelector('.highlight-code-block') if (codeElement) { hljs.highlightElement(codeElement) } }) </script> <template> <pre class="highlight-pre"> <code :class="`language-${language}`" class="highlight-code-block" v-html="getEscapedSlotContent()" ></code> </pre> </template>
使用方式
现在你直接在插槽里写原生HTML就行,不用手动转义:
<HighlightComponent language="html"> <html> <head> <title>我的测试页面</title> </head> <body> <h1 style="color: red;">Hello World!</h1> </body> </html> </HighlightComponent>
方案二:用v-pre指令快速处理静态代码
如果你的插槽内容只是纯静态的代码示例,不需要动态渲染,那可以用Vue的v-pre指令跳过编译,直接保留原始文本:
<HighlightComponent> <div v-pre> <html> <head></head> <body> <p>这是静态代码示例</p> </body> </html> </div> </HighlightComponent>
注意:这个方案需要给代码外层套一个带v-pre的元素,组件里要确保只提取内部的代码内容,避免外层div标签被展示出来。
方案三:自定义全局过滤器简化转义
如果你在多个组件里都需要转义HTML,可以全局注册一个过滤器,复用转义逻辑:
// 在main.js里注册全局过滤器 import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.config.globalProperties.$escapeHtml = (str) => { return str .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') } app.mount('#app')
然后在你的高亮组件里直接使用这个过滤器:
<template> <pre v-highlightjs> <code v-html="$escapeHtml(rawSlotContent)"></code> </pre> </template>
不过这个方案还是需要你先获取插槽的原始内容,本质和方案一的核心逻辑一致。
最后提醒一句:如果插槽内容来自用户输入,一定要确保转义逻辑覆盖所有特殊字符,避免XSS安全风险哦!
内容的提问来源于stack exchange,提问作者Andy Schneider
相关产品推荐
相关产品推荐

