172 lines
3.1 KiB
Vue
172 lines
3.1 KiB
Vue
<template>
|
|
<div class="markdown-renderer" v-html="renderedHtml"></div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { marked } from 'marked'
|
|
import hljs from 'highlight.js'
|
|
import 'highlight.js/styles/github.css'
|
|
|
|
interface Props {
|
|
content: string
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
|
|
// 配置 marked
|
|
marked.setOptions({
|
|
highlight: function(code: string, lang: string) {
|
|
if (lang && hljs.getLanguage(lang)) {
|
|
return hljs.highlight(code, { language: lang }).value
|
|
}
|
|
return hljs.highlightAuto(code).value
|
|
},
|
|
breaks: true,
|
|
gfm: true,
|
|
})
|
|
|
|
const renderedHtml = computed(() => {
|
|
if (!props.content) return ''
|
|
try {
|
|
return marked.parse(props.content) as string
|
|
} catch (e) {
|
|
return '<p>渲染出错</p>'
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.markdown-renderer {
|
|
font-size: 15px;
|
|
line-height: 1.8;
|
|
color: rgba(0, 0, 0, 0.85);
|
|
}
|
|
|
|
.markdown-renderer :deep(h1) {
|
|
font-size: 1.8em;
|
|
font-weight: 700;
|
|
margin: 0.5em 0;
|
|
padding-bottom: 0.3em;
|
|
border-bottom: 1px solid #eaecef;
|
|
}
|
|
|
|
.markdown-renderer :deep(h2) {
|
|
font-size: 1.5em;
|
|
font-weight: 600;
|
|
margin: 0.8em 0 0.4em;
|
|
padding-bottom: 0.25em;
|
|
border-bottom: 1px solid #eaecef;
|
|
}
|
|
|
|
.markdown-renderer :deep(h3) {
|
|
font-size: 1.25em;
|
|
font-weight: 600;
|
|
margin: 0.6em 0 0.3em;
|
|
}
|
|
|
|
.markdown-renderer :deep(h4),
|
|
.markdown-renderer :deep(h5),
|
|
.markdown-renderer :deep(h6) {
|
|
font-weight: 600;
|
|
margin: 0.5em 0;
|
|
}
|
|
|
|
.markdown-renderer :deep(p) {
|
|
margin: 0.8em 0;
|
|
}
|
|
|
|
.markdown-renderer :deep(code) {
|
|
padding: 0.2em 0.4em;
|
|
background: #f6f8fa;
|
|
border-radius: 4px;
|
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
.markdown-renderer :deep(pre) {
|
|
padding: 16px;
|
|
background: #f6f8fa;
|
|
border-radius: 8px;
|
|
overflow-x: auto;
|
|
margin: 1em 0;
|
|
}
|
|
|
|
.markdown-renderer :deep(pre code) {
|
|
padding: 0;
|
|
background: transparent;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
.markdown-renderer :deep(blockquote) {
|
|
margin: 1em 0;
|
|
padding: 0.5em 1em;
|
|
border-left: 4px solid #dfe2e5;
|
|
color: #6a737d;
|
|
background: #f6f8fa;
|
|
border-radius: 0 8px 8px 0;
|
|
}
|
|
|
|
.markdown-renderer :deep(blockquote p) {
|
|
margin: 0.3em 0;
|
|
}
|
|
|
|
.markdown-renderer :deep(ul),
|
|
.markdown-renderer :deep(ol) {
|
|
padding-left: 2em;
|
|
margin: 0.8em 0;
|
|
}
|
|
|
|
.markdown-renderer :deep(li) {
|
|
margin: 0.3em 0;
|
|
}
|
|
|
|
.markdown-renderer :deep(a) {
|
|
color: #1890ff;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.markdown-renderer :deep(a:hover) {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.markdown-renderer :deep(img) {
|
|
max-width: 100%;
|
|
border-radius: 8px;
|
|
margin: 1em 0;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.markdown-renderer :deep(hr) {
|
|
margin: 1.5em 0;
|
|
border: none;
|
|
border-top: 1px solid #dfe2e5;
|
|
}
|
|
|
|
.markdown-renderer :deep(table) {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 1em 0;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.markdown-renderer :deep(th),
|
|
.markdown-renderer :deep(td) {
|
|
padding: 10px 14px;
|
|
border: 1px solid #dfe2e5;
|
|
}
|
|
|
|
.markdown-renderer :deep(th) {
|
|
background: #f6f8fa;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.markdown-renderer :deep(tr:hover) {
|
|
background: #fafafa;
|
|
}
|
|
|
|
.markdown-renderer :deep(input[type="checkbox"]) {
|
|
margin-right: 0.5em;
|
|
}
|
|
</style>
|