starwait/components/Home/Blog/Marked.vue
2025-04-29 02:39:55 +08:00

124 lines
3.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import {Marked} from 'marked';
// 默认导入所有语言
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-light.css';
// 注册语言
// import hljs from 'highlight.js/lib/core';
// import javascript from 'highlight.js/lib/languages/javascript';
// hljs.registerLanguage('javascript', javascript);
const marked = new Marked();
// 自定义行号注入函数
const injectLineNumbers = (highlightedCode: string) => {
const lines = highlightedCode.split('\n')
// 移除最后一行空行(常见于代码块末尾的换行)
if (lines[lines.length - 1] === '') lines.pop()
// 为每行添加行号容器
return lines.map((line, index) => `<div class="code-line"><span class="line-number">${index + 1}</span><span class="line-content">${line}</span></div>`).join('')
}
marked.use({
async: true,
pedantic: false,
gfm: true,
silent: true,
renderer: {
code: ({text, lang}) => {
console.log(text);
const validLang = hljs.getLanguage(lang) ? lang : 'plaintext'
const highlighted = hljs.highlight(text, {language: lang}).value
console.log(highlighted)
const withLineNumbers = injectLineNumbers(highlighted)
return `<pre class="hljs ${validLang}"><code>${withLineNumbers}</code></pre>`;
}
}
})
const content = ref(`
# Hello Vue 3!
**Markdown 内容示例:**
- 列表项
- 另一项
\`\`\`javascript
// 代码块示例
function greet() {
console.log('Hello marked!');
}
\`\`\`
| 参数 | \t类型 | \t作用 | \t默认值 |
|:-----------|:---------|:---------------------------------------------|:----------------|
| breaks | \tboolean | \t将换行符 \\n 渲染为 <br>(类似 GitHub | \tfalse |
| gfm | \tboolean | \t启用 GitHub Flavored Markdown 扩展(表格、删除线等) | \ttrue |
| headerIds\t | boolean | \t自动为标题添加 id 属性(如 \`<h1 id="hello-world"></h1>\` | \ttrue |
| highlight\t | function | \t代码高亮处理函数需返回高亮后的 HTML | \tnull |
| renderer\t | object | \t自定义渲染器对象覆盖默认渲染逻辑 | \tnew Renderer() |
| sanitize\t | boolean | \t过滤危险 HTML 标签(防止 XSS 攻击) | \tfalse |
| sanitizer\t | function | \t自定义 HTML 过滤函数 | \t- |
| silent\t | boolean | \t静默模式忽略解析错误如未闭合的代码块 | \tfalse |
`);
const compiledMarkdown = ref(await marked.parse(content.value));
</script>
<template>
<div
ref="markdownContainer"
class="markdown-content"
v-html="compiledMarkdown"
/>
</template>
<style scoped lang="scss">
.markdown-content {
// 基础样式...
/* 代码块样式 */
:deep(pre) {
white-space: pre-wrap;
background: #cdcdcd;
padding: 15px;
border-radius: 5px;
code {
font-family: 'Consolas', 'Fira Code', monospace;
font-size: 14px;
line-height: 1.5;
white-space: pre;
}
/* 确保代码块正确换行 */
code {
display: block;
overflow-x: auto;
padding: 1em;
}
.code-line {
display: flex;
min-height: 1em; /* 防止空行高度塌陷 */
}
.line-number {
width: 40px;
padding-right: 12px;
color: #666;
text-align: right;
user-select: none;
flex-shrink: 0;
}
.line-content {
flex-grow: 1;
white-space: pre-wrap; /* 允许代码换行 */
}
}
}
</style>