Vue2 集成 markdown-it 要做哪些准备?
做技术项目时,经常碰到要把 Markdown 文本转成美观 HTML 展示的需求,比如博客文章、组件文档、帮助中心这些场景,Vue2 项目里想实现这功能,markdown-it 是个很趁手的工具,但不少同学刚接触时,会纠结“咋把 markdown-it 加到 Vue2 里?配置、插件、样式这些咋处理?” 下面用问答形式,把 Vue2 + markdown-it 从基础到进阶的知识点拆解开讲~
首先得把工具链搭起来,第一步是安装依赖,打开终端,在 Vue2 项目根目录执行 `npm install markdown-it`(用 yarn 就换 `yarn add markdown-it`),这一步是把 markdown-it 这个库拉到项目里,它能帮我们把 Markdown 语法解析成 HTML 字符串。然后得理解 markdown-it 的核心逻辑:它本质是个解析器,初始化一个实例后,调用 render
方法传入 Markdown 文本,就能得到对应的 HTML,所以在 Vue 组件里,我们要做的是 —— 引入库、初始化实例、调用解析方法。
举个简单例子,新建个组件,在 <script>
里引入:
import MarkdownIt from 'markdown-it' export default { data() { return { mdText: '## 这是个测试标题\n**加粗内容**' // 模拟从接口或编辑器拿到的 Markdown 内容 } }, methods: { renderMd() { const md = new MarkdownIt() // 初始化解析器实例 return md.render(this.mdText) // 把 Markdown 转成 HTML } } }
这样就完成了最基础的“引入 - 初始化 - 解析”流程,不过实际项目里,为了性能和代码整洁,一般会把解析逻辑放到 computed
或者封装成工具函数,后面展开讲~
怎么在 Vue2 组件里渲染 Markdown 内容到页面?
核心是“解析 + 安全渲染”两步走。
第一步:解析 Markdown 成 HTML
刚才提到用 markdownIt.render()
能生成 HTML 字符串,但直接写在方法里每次调用都新建实例,有点浪费性能,更优的做法是在 mounted
里初始化实例,存到 data
里复用:
export default { data() { return { md: null, // 存 markdown-it 实例 mdText: '# 我的第一篇 Vue2 + Markdown 文章', renderedHtml: '' // 存解析后的 HTML } }, mounted() { this.md = new MarkdownIt() // 初始化实例,可配置参数 this.renderedHtml = this.md.render(this.mdText) } }
第二步:用 v-html
渲染到页面
Vue 里渲染 HTML 字符串得用 v-html
指令,所以模板里写:
<template> <div class="markdown-container" v-html="renderedHtml"></div> </template>
但必须注意安全问题!Markdown 内容来自用户输入(比如开放编辑器),直接渲染可能被注入 XSS 攻击(比如用户写 <script>alert(1)</script>
这种代码),这时候建议结合 DOMPurify
这类库,先过滤危险标签再渲染,步骤是:
- 安装
DOMPurify
:npm install dompurify
- 引入后过滤 HTML:
import DOMPurify from 'dompurify' // 解析后过滤 const cleanHtml = DOMPurify.sanitize(md.render(this.mdText)) this.renderedHtml = cleanHtml
markdown-it 常用配置有哪些?能解决啥问题?
markdown-it 初始化时可以传配置对象,调整解析规则和渲染行为,常见需求对应配置如下:
控制 HTML 标签是否转义
默认 html: false
,意思是 Markdown 里写的 HTML 标签会被转义(<div>
变成 <div>
),如果想让 Markdown 里的 HTML 直接生效(比如写自定义组件 <MyComponent />
),得开 html: true
:
new MarkdownIt({ html: true })
让换行符转成 <br>
默认 Markdown 里的换行(\n
)不会转成 <br>
,得敲两个空格 + 换行才生效,如果想让单换行也转 <br>
,开 breaks: true
:
new MarkdownIt({ breaks: true })
自动加 ID(做锚点用) # 标题
)渲染后是 <h1>标题</h1>
,没 ID 不好做锚点跳转,可以通过配置 headingIds: true
让标题自动生成 ID(基于内容):
new MarkdownIt({ headingIds: true }) // 渲染后:<h1 id="标题">标题</h1>(实际会做 slug 处理,比如中文转拼音或保留字符)
代码块高亮(结合 highlight.js)
想让代码块带语法高亮,得配合 highlight.js
,步骤:
- 安装
highlight.js
:npm install highlight.js
- 初始化时配置高亮函数:
import hljs from 'highlight.js' new MarkdownIt({ highlight: function (str, lang) { if (lang && hljs.getLanguage(lang)) { try { return hljs.highlight(str, { language: lang }).value } catch (err) {} } return '' // 没匹配到语言,返回空(或默认处理) } })
这样代码块
<pre><code>
会被加上高亮样式,再引入highlight.js
的主题 CSS(import 'highlight.js/styles/atom-one-light.css'
),就能实现美观的代码高亮。
想给 markdown-it 加插件扩展功能,咋操作?
markdown-it 生态有很多实用插件,比如生成目录、加锚点、优化表格渲染等,以标题锚点(markdown-it-anchor)和目录生成(markdown-it-table-of-contents)为例,看怎么集成:
案例 1:给标题加锚点(markdown-it-anchor)
- 安装插件:
npm install markdown-it-anchor
- 引入并注册到 markdown-it 实例:
import MarkdownIt from 'markdown-it' import anchor from 'markdown-it-anchor'
const md = new MarkdownIt()
md.use(anchor, {
permalink: true, // 显示锚点链接(小图标或链接)
permalinkSymbol: '#' // 锚点符号,也可以用 FontAwesome 图标
})
``会变成
#`,点锚点能跳转到对应位置。
案例 2:生成文章目录(markdown-it-table-of-contents)
- 安装插件:
npm install markdown-it-table-of-contents
- 注册并配置:
import toc from 'markdown-it-table-of-contents'
md.use(toc, {
includeLevel: [1, 2, 3], // 包含 h1 - h3 标题
headingText: '文章目录' // 目录标题文字
})
然后在 Markdown 里写 `[toc]` 关键词,渲染后会自动生成目录列表。
### Vue2 里 markdown-it 渲染的内容没样式,咋解决?
Markdown 转成 HTML 后,默认是“裸”标签(只有语义,没样式),得自己加 CSS,有两种思路:
#### 思路 1:自己写样式
给常见标签(`h1 - h6`、`p`、`ul/ol`、`code`、`pre`、`blockquote` 等)写样式。
```css
.markdown-container h1 {
font-size: 28px;
margin-bottom: 16px;
border-bottom: 1px solid #eee;
padding-bottom: 8px;
}
.markdown-container code {
background: #f5f5f5;
padding: 2px 4px;
border-radius: 4px;
}
/* 其他标签... */
好处是完全自定义,贴合项目风格;缺点是要写很多代码,对新手不友好。
思路 2:用现成样式库
最火的是 github-markdown-css
,它模拟 GitHub 上 Markdown 渲染的样式,开箱即用,步骤:
- 安装:
npm install github-markdown-css
- 引入样式:
import 'github-markdown-css'
- 给渲染容器加类名:
<div class="markdown-body" v-html="renderedHtml"></div>
这样渲染出的内容直接继承 GitHub 风格,省了写样式的功夫,类似的还有 markdown-css-themes
这类库,提供多种预设主题,按需选择就行。
大量 Markdown 内容渲染,性能咋优化?
如果页面要渲染几万字的 Markdown(比如长文档),直接解析+渲染可能卡页面,可以从这几点优化:
缓存解析结果
Markdown 内容不变(比如静态文章),把解析后的 HTML 存起来,避免重复解析,用 computed
+ 缓存逻辑:
computed: {
renderedHtml() {
if (this.cacheHtml) return this.cacheHtml
const html = this.md.render(this.mdText)
this.cacheHtml = html // 存到 data 里
return html
}
}
防抖 + 异步渲染(针对实时预览场景)
如果做“编辑器实时预览”(比如左边输入,右边实时更行),输入时频繁解析会很卡,用 lodash.debounce
防抖,延迟解析:
import { debounce } from 'lodash'
export default {
data() {
return {
mdText: '',
renderedHtml: ''
}
},
methods: {
handleInput: debounce(function (val) {
this.renderedHtml = this.md.render(val)
}, 300) // 输入停止 300ms 后再解析
}
}
模板里绑定输入事件:
<textarea v-model="mdText" @input="handleInput($event.target.value)"></textarea>
分片渲染长内容 极长(比如几万行),一次性插入 DOM 会阻塞渲染,可以把 HTML 拆成小块,用 requestAnimationFrame
分批插入,类似虚拟列表思路,不过这对 Vue2 来说稍复杂,小项目一般用前两种方法就够。
和其他富文本方案比,markdown-it 在 Vue2 里有啥独特优势?
常见富文本方案有 Quill、TinyMCE、Slate 等,和它们比,markdown-it 适合场景,优势很明显:
- 轻量灵活:核心库才几十 KB,加载快;插件按需引入,不会冗余。
- 学习成本低:只要懂 Markdown 语法(程序员基本都熟),不需要学复杂的富文本编辑器操作(比如选字体、调格式)。
- 扩展性强:插件生态丰富,从代码高亮到流程图渲染(markdown-it-mermaid),想加功能只需要装插件+配置。
- 版本稳定:Vue2 已经是成熟框架,markdown-it 也迭代多年,兼容性和稳定性经过大量项目验证。
比如做开源组件文档站、个人技术博客,用 markdown-it 配合 Vue2 快速搭起“写 Markdown -> 解析 -> 美观展示”的流程,比用重型富文本编辑器效率高太多。
实际项目里,Vue2 + markdown-it 有哪些避坑点?
踩过这些“坑”,能少走弯路:
v-html 的 XSS 风险
前面提过,用户输入的内容必须过滤!哪怕是内部系统,也别偷懒,用 DOMPurify
这类库过滤后再渲染,避免脚本注入。
插件版本兼容问题
不同 markdown-it 版本对插件的支持可能不同,markdown-it@13.x 和某些老插件不兼容,装插件前看 npm 文档里的版本要求,或者直接看 GitHub 仓库的 README。
自定义渲染器时破坏默认逻辑
如果要自定义某类标签的渲染(比如把所有 <a>
改成带 target="_blank"
),需要懂 markdown-it 的 Renderer
机制,直接改 renderer.rules
时,要保留原逻辑再扩展,否则可能导致解析错误,示例:
const md = new MarkdownIt()
// 自定义链接渲染,保留原逻辑并加 target
const defaultLinkRender = md.renderer.rules.link_open
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
tokens[idx].attrPush(['target', '_blank']) // 加属性
return defaultLinkRender(tokens, idx, options, env, self) // 调用默认渲染
}
样式冲突
如果项目里有全局样式(比如重置样式 normalize.css
),可能和 markdown 渲染的标签样式冲突,建议给渲染容器加独特类名(class="md-render"
),然后用后代选择器写样式(.md-render h1 { ... }
),隔离样式作用域。
从基础集成到性能优化,再到插件拓展和避坑,Vue2 里用 markdown-it 实现 Markdown 渲染的核心点基本覆盖啦~ 实际项目里,根据需求选配置、挑插件、搭样式,就能快速做出“写 Markdown 像写笔记,渲染后像专业文档”的效果,要是你在开发文档系统、技术博客这类项目,不妨试试这套组合,轻量化又灵活,能省不少开发时间~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
npm install markdown-it-table-of-contents
import toc from 'markdown-it-table-of-contents'
然后在 Markdown 里写 `[toc]` 关键词,渲染后会自动生成目录列表。
### Vue2 里 markdown-it 渲染的内容没样式,咋解决?
Markdown 转成 HTML 后,默认是“裸”标签(只有语义,没样式),得自己加 CSS,有两种思路:
#### 思路 1:自己写样式
给常见标签(`h1 - h6`、`p`、`ul/ol`、`code`、`pre`、`blockquote` 等)写样式。
```css
.markdown-container h1 {
font-size: 28px;
margin-bottom: 16px;
border-bottom: 1px solid #eee;
padding-bottom: 8px;
}
.markdown-container code {
background: #f5f5f5;
padding: 2px 4px;
border-radius: 4px;
}
/* 其他标签... */
github-markdown-css
,它模拟 GitHub 上 Markdown 渲染的样式,开箱即用,步骤: npm install github-markdown-css
import 'github-markdown-css'
<div class="markdown-body" v-html="renderedHtml"></div>
这样渲染出的内容直接继承 GitHub 风格,省了写样式的功夫,类似的还有 markdown-css-themes
这类库,提供多种预设主题,按需选择就行。
computed
+ 缓存逻辑: lodash.debounce
防抖,延迟解析: requestAnimationFrame
分批插入,类似虚拟列表思路,不过这对 Vue2 来说稍复杂,小项目一般用前两种方法就够。DOMPurify
这类库过滤后再渲染,避免脚本注入。 <a>
改成带 target="_blank"
),需要懂 markdown-it 的 Renderer
机制,直接改 renderer.rules
时,要保留原逻辑再扩展,否则可能导致解析错误,示例: normalize.css
),可能和 markdown 渲染的标签样式冲突,建议给渲染容器加独特类名(class="md-render"
),然后用后代选择器写样式(.md-render h1 { ... }
),隔离样式作用域。 版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。