fix: HTML 渲染异常 (#152)
* fix: 修复 `API` 版本 HTML 会被渲染的问题[#146] * chore: version 2.8.1
This commit is contained in:
parent
2c509c329f
commit
21fb4f817c
|
@ -1,3 +1,10 @@
|
|||
## v2.8.1
|
||||
|
||||
`2023-02-27`
|
||||
|
||||
### BugFix
|
||||
- 修复 `API` 版本不是 `Markdown` 时,普通 `HTML` 代码会被渲染的问题 [#146]
|
||||
|
||||
## v2.8.0
|
||||
|
||||
`2023-02-27`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "chatgpt-web",
|
||||
"version": "2.8.0",
|
||||
"version": "2.8.1",
|
||||
"private": false,
|
||||
"description": "ChatGPT Web",
|
||||
"author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import type { App, Directive } from 'vue'
|
||||
import hljs from 'highlight.js'
|
||||
import { includeCode } from '@/utils/format'
|
||||
|
||||
hljs.configure({ ignoreUnescapedHTML: true })
|
||||
|
||||
function highlightCode(el: HTMLElement) {
|
||||
if (includeCode(el.textContent))
|
||||
hljs.highlightBlock(el)
|
||||
}
|
||||
|
||||
export default function setupHighlightDirective(app: App) {
|
||||
const highLightDirective: Directive<HTMLElement> = {
|
||||
mounted(el: HTMLElement) {
|
||||
highlightCode(el)
|
||||
},
|
||||
updated(el: HTMLElement) {
|
||||
highlightCode(el)
|
||||
},
|
||||
}
|
||||
|
||||
app.directive('highlight', highLightDirective)
|
||||
}
|
|
@ -1 +1,6 @@
|
|||
export function setupDirectives() {}
|
||||
import type { App } from 'vue'
|
||||
import setupHighlightDirective from './highlight'
|
||||
|
||||
export function setupDirectives(app: App) {
|
||||
setupHighlightDirective(app)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import { setupDirectives } from './directives'
|
||||
import { setupAssets } from '@/plugins'
|
||||
import { setupStore } from '@/store'
|
||||
import { setupRouter } from '@/router'
|
||||
|
@ -10,6 +11,8 @@ async function bootstrap() {
|
|||
|
||||
setupStore(app)
|
||||
|
||||
setupDirectives(app)
|
||||
|
||||
await setupRouter(app)
|
||||
|
||||
app.mount('#app')
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// 转义 HTML 字符
|
||||
export function encodeHTML(source: string) {
|
||||
return source
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
}
|
||||
|
||||
// 判断是否为代码块
|
||||
export function includeCode(text: string | null | undefined) {
|
||||
const regexp = /^(?:\s{4}|\t).+/gm
|
||||
return !!(text?.includes(' = ') || text?.match(regexp))
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
function includeCode(text: string | null | undefined) {
|
||||
const regexp = /^(?:\s{4}|\t).+/gm
|
||||
return !!(text?.includes(' = ') || text?.match(regexp))
|
||||
}
|
||||
|
||||
export default includeCode
|
|
@ -3,6 +3,7 @@ import { computed } from 'vue'
|
|||
import { marked } from 'marked'
|
||||
import hljs from 'highlight.js'
|
||||
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
||||
import { encodeHTML } from '@/utils/format'
|
||||
|
||||
interface Props {
|
||||
inversion?: boolean
|
||||
|
@ -15,12 +16,19 @@ const props = defineProps<Props>()
|
|||
|
||||
const { isMobile } = useBasicLayout()
|
||||
|
||||
marked.setOptions({
|
||||
renderer: new marked.Renderer(),
|
||||
highlight(code) {
|
||||
return hljs.highlightAuto(code).value
|
||||
},
|
||||
})
|
||||
const renderer = new marked.Renderer()
|
||||
|
||||
renderer.html = (html) => {
|
||||
return `<p>${encodeHTML(html)}</p>`
|
||||
}
|
||||
|
||||
renderer.code = (code, language) => {
|
||||
const validLang = !!(language && hljs.getLanguage(language))
|
||||
const highlighted = validLang ? hljs.highlight(language, code).value : code
|
||||
return `<pre><code class="hljs ${language}">${highlighted}</code></pre>`
|
||||
}
|
||||
|
||||
marked.setOptions({ renderer })
|
||||
|
||||
const wrapClass = computed(() => {
|
||||
return [
|
||||
|
@ -35,9 +43,10 @@ const wrapClass = computed(() => {
|
|||
})
|
||||
|
||||
const text = computed(() => {
|
||||
if (props.text && !props.inversion)
|
||||
return marked(props.text)
|
||||
return props.text
|
||||
const value = props.text ?? ''
|
||||
if (!props.inversion)
|
||||
return marked(value)
|
||||
return value
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
Loading…
Reference in New Issue