Markdown写作
更新: 2/10/2025 字数: 0 字 时长: 0 分钟
VitePress使用 markdown-it 作为 md 语法解析器,md 基础语法可以参考基本撰写和格式语法,此外 vitepress 还提供了更多个性化语法,具体可以参考Markdown 扩展。
锚点
md 文档中的标题会自动生成锚点链接,可以通过页面路径#锚点名称
的形式跳转到文章的具体位置,还可以通过如下格式自定义锚点名称
# 标题 {#自定义锚点名称}
定义后便可以通过最新的锚点名称定位页面位置(此时原名称不可用),本节的标题就修改了锚点名称,可以点击标题查看效果
资源链接
页面链接
页面之间的链接可以使用相对路径或绝对路径,如果使用绝对路径是相对于文档主目录决定的
[Home](/) <!-- 跳转到根目录下 index.md -->
[foo](/foo/) <!-- 跳转到 /foo/index.md -->
[heading](./#heading) <!-- 跳转到当前页面的heading锚点 -->
<!-- 可以写扩展名,也可以省略扩展名 -->
[bar - three](../bar/three)
[bar - three](../bar/three.md)
[bar - three](../bar/three.html)
静态资源链接
所有的 md 文件都会被编译成 Vue 文件,所以任何绝对路径或相对路径的静态资源引用都会交由 Vite 处理。小于 4kb 的图片会转为 Base64 内嵌在页面中,未被引用的资源也不会被复制到输出目录中
如果文档部署在非根 URL 上,需要在 config 中设置 base 路径,此时的绝对路径静态资源引用不需要额外增加基础路径,因为 vite 会识别并处理。但如果链接存放在一个动态变量中时,则不会被 vite 识别,这与 Vue 项目中的静态资源处理方式一致
此时建议使用 vitepress 提供的 withBase
api 包装路径
<script setup>
import { withBase, useData } from 'vitepress'
const { theme } = useData()
</script>
<template>
<img :src="withBase(theme.logoPath)" />
</template>
TIP
md
语法插入的图片会保持比例拉伸填满宽度,如果需要自定义图片大小可以使用HTML
标签
<img src="" alt="" width="" style="margin: 0 auto" />
公共目录
如果有不希望 Vite 处理的静态资源,可以放在工作目录/public
文件夹下, public 文件夹是 Vue 3 的静态资源文件夹,打包时会将内部的文件原封不动的放在打包后的根路径中(所以需要注意 public 内文件夹不要与文档文件夹重名),引用 public 下的文件时应始终使用 /
开头的绝对路径
有一个例外是:如果从 md 页面链接 public 下的 HTML 页面,路由器将默认产生 404,这时可以通过 pathname://
协议正确链接页面,格式为<pathname:///xxx.html>
pathname 协议仅支持在 md 文件中链接,并且默认在新标签页打开,也可以使用如下的方式直接在本页面打开
<!-- 此时不再需要pathname协议 -->
[link](/xxx.html){target="\_self"}
FrontMatter
用于配置单个页面,会覆盖 config 中定义的全局级别配置;支持yaml
、json
等格式,必须定义在页面顶部
定义的字段还可以作为页面变量,通过{{$frontmatter}}
形式引用,本页标题就是引用的变量
---
title: Blogging Like a Hacker
lang: en-US
---
# {{ $frontmatter.title }}
GitHub 风格的表格
输入
| Tables | Are | Cool |
| ------------- | :-----------: | ----: |
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
输出
Tables | Are | Cool |
---|---|---|
col 3 is | right-aligned | $1600 |
col 2 is | centered | $12 |
zebra stripes | are neat | $1 |
Emoji 🎉
输入
:tada: :100:
输出
🎉 💯
这里可以找到所有支持的 emoji 列表。
自定义容器
输入
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger STOP
This is a dangerous warning.
:::
::: details
This is a details block.
:::
输出
INFO
This is an info box.
TIP
This is a tip.
WARNING
This is a warning.
STOP
This is a dangerous warning.
点我查看代码
console.log('Hello, VitePress!')
此外,可以通过在站点配置中添加以下内容来全局设置自定义标题,如果不是用英语书写,这会很有帮助:
// config.ts
export default defineConfig({
// ...
markdown: {
container: {
tipLabel: '提示',
warningLabel: '警告',
dangerLabel: '危险',
infoLabel: '信息',
detailsLabel: '详细信息'
}
}
// ...
})
GitHub 风格的警报
VitePress 同样支持以标注的方式渲染 GitHub 风格的警报。它们和自定义容器的渲染方式相同。
> [!NOTE]
> 强调用户在快速浏览文档时也不应忽略的重要信息。
> [!TIP]
> 有助于用户更顺利达成目标的建议性信息。
> [!IMPORTANT]
> 对用户达成目标至关重要的信息。
> [!WARNING]
> 因为可能存在风险,所以需要用户立即关注的关键内容。
> [!CAUTION]
> 行为可能带来的负面影响。
NOTE
强调用户在快速浏览文档时也不应忽略的重要信息。
TIP
有助于用户更顺利达成目标的建议性信息。
IMPORTANT
对用户达成目标至关重要的信息。
WARNING
因为可能存在风险,所以需要用户立即关注的关键内容。
CAUTION
行为可能带来的负面影响。
代码功能
vitepress 使用 Shiki 实现 MD 代码块高亮显示,支持的语言可以查看这份列表
行高亮显示
通过在语言名后跟行号范围,可以突出显示指定的行
指定格式可以是单行{4}
,范围{5-8}
或组合{4,7-13,16}
,也可以直接使用// [!code hl]
注释实现单行高亮显示
```js{3}
let a = 1 // [!code hl]
let b = 2
console.log(a, b)
```
let a = 1
let b = 2
console.log(a, b)
TIP
如果想在代码块中输入```
,需要将外层的代码块语法修改为四个点````
行聚焦显示
使用[!code focus]
注释可以聚焦单行,其余部分模糊显示(hover 时恢复)
```js
let a = 1 // [!code focus]
let b = 2
console.log(a, b) // [!code focus]
```
let a = 1
let b = 2
console.log(a, b)
Diff 效果
添加注释[!code --]
或[!code ++]
可以显示增删行效果
```js
let a = 1 // [!code --]
let a = 2 // [!code ++]
console.log(a)
```
let a = 1
let a = 2
console.log(a)
错误或警告效果
添加注释[!code warning]
或[!code error]
可以对应增加黄色和红色的底色
```js
let a = 1 // [!code warning]
let a = 2 // [!code error]
console.log(a)
```
let a = 1
let a = 2
console.log(a)
导入代码片段
可以通过下面的语法来从现有文件中导入代码片段:
<<< @/filepath
此语法同时支持行高亮:
<<< @/filepath{highlightLines}
输入
<<< @/41_前端开发/22_vitepress/snippets/snippet.js{2}
Code file
export default function () {
// ..
}
输出
export default function () {
// ..
}
TIP
@
的值对应于源代码根目录,默认情况下是 VitePress 项目根目录,除非配置了 srcDir
。或者也可以从相对路径导入:
<<< @/41_前端开发/22_vitepress/snippets/snippet.js
也可以使用 VS Code region 来只包含代码文件的相应部分。可以在文件目录后面的 #
符号后提供一个自定义的区域名:
输入
<<< @/41_前端开发/22_vitepress/snippets/snippet-with-region.js#snippet{1}
Code file
// #region snippet
function foo() {
// ..
}
// #endregion snippet
export default foo
输出
function foo() {
// ..
}
也可以像这样在大括号内({}
)指定语言:
<<< @/41_前端开发/22_vitepress/snippets/snippet.cs{c#}
<!-- 带行高亮: -->
<<< @/41_前端开发/22_vitepress/snippets/snippet.cs{1,2,4-6 c#}
<!-- 带行号: -->
<<< @/41_前端开发/22_vitepress/snippets/snippet.cs{1,2,4-6 c#:line-numbers}
如果无法从文件扩展名推测出源语言,这将会很有帮助
代码组
可以像这样对多个代码块进行分组:
输入
::: code-group
```js [config.js]
/**
* @type {import('vitepress').UserConfig}
*/
const config = {
// ...
}
export default config
```
```ts [config.ts]
import type { UserConfig } from 'vitepress'
const config: UserConfig = {
// ...
}
export default config
```
:::
输出
/**
* @type {import('vitepress').UserConfig}
*/
const config = {
// ...
}
export default config
import type { UserConfig } from 'vitepress'
const config: UserConfig = {
// ...
}
export default config
也可以在代码组中导入代码片段:
输入
::: code-group
<!-- 文件名默认用作标题 -->
<<< @/41_前端开发/22_vitepress/snippets/snippet.js
<!-- 也可以提供定制的代码组 -->
<<< @/41_前端开发/22_vitepress/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]
:::
输出
export default function () {
// ..
}
function foo() {
// ..
}
导入 Markdown
可以导入其他 md 文件(不存在不会报错),还可以在文件名后指定显示的行号 <!--@ include: @/41_前端开发/22_vitepress/snippets/importDemo.md{3,}-->
,表示显示第三行以及之后的内容,所选范围格式还可以是 {,10}
、{2,8}
代码块中的语法高亮
VitePress 使用 Shiki 在 Markdown 代码块中使用彩色文本实现语法高亮。Shiki 支持多种编程语言。需要做的就是将有效的语言别名附加到代码块的开头:
输入
```js
export default {
name: 'MyComponent',
// ...
}
```
```html
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
```
输出
export default {
name: 'MyComponent'
// ...
}
<ul>
<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
</ul>
在 Shiki 的代码仓库中,可以找到合法的编程语言列表。
还可以全局配置中自定义语法高亮主题。
在代码块中实现行高亮
输入
```js{4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
输出
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
除了单行之外,还可以指定多个单行、多行,或两者均指定:
- 多行:例如
{5-8}
、{3-10}
、{10-17}
- 多个单行:例如
{4,7,9}
- 多行与单行:例如
{4,7-13,16,23-27,40}
输入
```js{1,4,6-8}
export default { // Highlighted
data () {
return {
msg: `Highlighted!
This line isn't highlighted,
but this and the next 2 are.`,
motd: 'VitePress is awesome',
lorem: 'ipsum'
}
}
}
```
输出
export default { // Highlighted
data () {
return {
msg: `Highlighted!
This line isn't highlighted,
but this and the next 2 are.`,
motd: 'VitePress is awesome',
lorem: 'ipsum',
}
}
}
也可以使用 // [!code highlight]
注释实现行高亮。
输入
```js
export default {
data () {
return {
msg: 'Highlighted!' // [!code highlight]
}
}
}
```
输出
export default {
data() {
return {
msg: 'Highlighted!'
}
}
}
代码块中聚焦
在某一行上添加 // [!code focus]
注释将聚焦它并模糊代码的其他部分。
此外,可以使用 // [!code focus:<lines>]
定义要聚焦的行数。
输入
```js
export default {
data () {
return {
msg: 'Focused!' // [!code focus]
}
}
}
```
输出
export default {
data() {
return {
msg: 'Focused!'
}
}
}
代码块中的颜色差异
在某一行添加 // [!code --]
或 // [!code ++]
注释将会为该行创建 diff,同时保留代码块的颜色。
输入
```js
export default {
data () {
return {
msg: 'Removed' // [!code --]
msg: 'Added' // [!code ++]
}
}
}
```
输出
export default {
data() {
return {
msg: 'Removed'
msg: 'Added'
}
}
}
高亮“错误”和“警告”
在某一行添加 // [!code warning]
或 // [!code error]
注释将会为该行相应的着色。
输入
```js
export default {
data () {
return {
msg: 'Error', // [!code error]
msg: 'Warning' // [!code warning]
}
}
}
```
输出
export default {
data() {
return {
msg: 'Error',
msg: 'Warning'
}
}
}
包含 markdown 文件
可以像这样在一个 markdown 文件中包含另一个 markdown 文件,甚至是内嵌的。
TIP
也可以使用 @
,它的值对应于源代码根目录,默认情况下是 VitePress 项目根目录,除非配置了 srcDir
。
例如,可以这样用相对路径包含 Markdown 文件:
输入
# Docs
## Basics
<!--@include: ./parts/basics.md-->
Part file (parts/basics.md
)
Some getting started stuff.
### Configuration
Can be created using `.foorc.json`.
等价代码
# Docs
## Basics
Some getting started stuff.
### Configuration
Can be created using `.foorc.json`.
它还支持选择行范围:
输入
# Docs
## Basics
<!--@include: ./parts/basics.md{3,}-->
Part file (parts/basics.md
)
Some getting started stuff.
### Configuration
Can be created using `.foorc.json`.
等价代码
# Docs
## Basics
### Configuration
Can be created using `.foorc.json`.
所选行范围的格式可以是: {3,}
、 {,10}
、{1,10}
WARNING
如果指定的文件不存在,这将不会产生错误。因此,在使用这个功能的时候请保证内容按预期呈现。
数学方程
现在这是可选的。要启用它,需要安装 markdown-it-mathjax3
,在配置文件中设置markdown.math
为 true
:
npm add -D markdown-it-mathjax3
// .vitepress/config.ts
export default {
markdown: {
math: true
}
}
输入
When $a \ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
**Maxwell's equations:**
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$ |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_ |
输出
When
Maxwell's equations:
equation | description |
---|---|
divergence of | |
curl of | |
wha? |
使用 Vue
VitePress 的 md 文件通过 markdown-it 解析后,被渲染为 Vue 页面,所以可以直接在 md 文件中使用任何 Vue 功能(需要遵守 SSR 渲染相关规则),包括插值语法、HTML 标签、Vue 指令、script setup
、css预处理器
(需安装)等
md 文件的主体内容就相当于 <template>
标签,此外需要用到局部范围的样式时,应该使用<style module>
代替<style scoped>
默认情况下```
代码块都会被 v-pre 包裹,不会识别内部的插值语法,如果需要识别,则可以在语言名后添加-vue
后缀
```js-vue
Hello {{ 1 + 1 }}
```
Hello 2
使用组件
只需要添加<script setup>
标签,并在标签中正常引入组件,即可在 md 中使用。如果一个组件要在大多数页面上使用,可以全局注册组件,例如 vitepress 默认主题中全局注册了 Badge 组件(源码位置:vitepress\dist\client\theme-default\without-fonts.js
)
<Badge text="info" type="info" />
<Badge text="tip" type="tip" />
<Badge text="warning" type="warning" />
<Badge text="danger" type="danger" />
也可以自定义主题,并在.VitePress/theme/index.js
中使用enhanceApp
配置公共组件。
import DefaultTheme from 'VitePress/theme'
import XXX from 'xxx'
export default {
...DefaultTheme,
enhanceApp(ctx) {
DefaultTheme.enhanceApp(ctx)
ctx.app.component('XXX', XXX)
}
}
VitePress 全局注册了<ClientOnly />
组件可以用于包裹非SSR
友好的组件,被包裹的组件在渲染到客户端后才会开始执行,避免SSR
过程中报错
如果需要使用 <Teleport>
,默认只支持传送到 body,如需传送其他目标,可以包裹在 <ClientOnly>
组件中
<ClientOnly>
<Teleport to="#modal">
<div>
// ...
</div>
</Teleport>
</ClientOnly>
在 Markdown 中导入组件
如果一个组件只被几个页面使用,建议在使用它们的地方显式导入它们。这使它们可以正确地进行代码拆分,并且仅在显示相关页面时才加载:
<script setup>
import CustomComponent from '../components/CustomComponent.vue'
</script>
# Docs
This is a .md using a custom component
<CustomComponent />
## More docs
...
注册全局组件
如果一个组件要在大多数页面上使用,可以通过自定义 Vue 实例来全局注册它们。
重要
确保自定义组件的名称包含连字符或采用 PascalCase。否则,它将被视为内联元素并包裹在 <p>
标签内,这将导致激活不匹配,因为 <p>
不允许将块元素放置在其中。
在标题中使用组件
可以在标题中使用 Vue 组件,但请注意以下语法之间的区别:
Markdown | 输出的 HTML | 被解析的标题 |
---|---|---|
| <h1>text <Tag/></h1> | text |
| <h1>text <code><Tag/></code></h1> | text <Tag/> |
被 <code>
包裹的 HTML 将按原样显示,只有未包裹的 HTML 才会被 Vue 解析。
TIP
输出 HTML 由 Markdown-it 完成,而解析的标题由 VitePress 处理 (并用于侧边栏和文档标题)。
转义
可以通过使用 v-pre
指令将它们包裹在 <span>
或其他元素中来转义 Vue 插值:
输入
This <span v-pre>{{ will be displayed as-is }}</span>
输出
This {{ will be displayed as-is }}
也可以将整个段落包装在 v-pre
自定义容器中:
::: v-pre
{{ This will be displayed as-is }}`
:::
输出
{{ This will be displayed as-is }}
代码块中不转义
默认情况下,代码块是受到保护的,都会自动使用 v-pre
包装,因此内部不会处理任何 Vue 语法。要在代码块内启用 Vue 插值语法,可以在代码语言后附加 -vue
后缀,例如 js-vue
:
输入
```js-vue
Hello {{ 1 + 1 }}
```
输出
Hello 2
请注意,这可能会让某些字符不能正确地进行语法高亮显示。
使用 CSS 预处理器
VitePress 内置支持 CSS 预处理器:.scss
、.sass
、.less
、.styl
和 .stylus
文件。无需为它们安装 Vite 专用插件,但必须安装相应的预处理器:
# .scss and .sass
npm install -D sass
# .less
npm install -D less
# .styl and .stylus
npm install -D stylus
然后可以在 Markdown 和主题组件中使用以下内容:
<style lang="sass">
.title
font-size: 20px
</style>
使用 teleport 传递组件内容
VitePress 目前只有使用 teleport 传送到 body 的 SSG 支持。对于其他地方,可以将它们包裹在内置的 <ClientOnly>
组件中,或者通过 postRender 钩子将 teleport 标签注入到最终页面 HTML 中的正确位置。
Details
<script setup lang="ts">
import { ref } from 'vue'
const showModal = ref(false)
</script>
<template>
<button class="modal-button" @click="showModal = true">Show Modal</button>
<Teleport to="body">
<Transition name="modal">
<div v-show="showModal" class="modal-mask">
<div class="modal-container">
<p>Hello from the modal!</p>
<div class="model-footer">
<button class="modal-button" @click="showModal = false">Close</button>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>
<style scoped>
.modal-mask {
position: fixed;
z-index: 200;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.3s ease;
}
.modal-container {
width: 300px;
margin: auto;
padding: 20px 30px;
background-color: var(--vp-c-bg);
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
}
.model-footer {
margin-top: 8px;
text-align: right;
}
.modal-button {
padding: 4px 8px;
border-radius: 4px;
border-color: var(--vp-button-alt-border);
color: var(--vp-button-alt-text);
background-color: var(--vp-button-alt-bg);
}
.modal-button:hover {
border-color: var(--vp-button-alt-hover-border);
color: var(--vp-button-alt-hover-text);
background-color: var(--vp-button-alt-hover-bg);
}
.modal-enter-from,
.modal-leave-to {
opacity: 0;
}
.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
transform: scale(1.1);
}
</style>
<ClientOnly>
<Teleport to="#modal">
<div>
// ...
</div>
</Teleport>
</ClientOnly>
文档配置
图片懒加载
通过在配置文件中将 lazyLoading
设置为 true
,可以为通过 markdown 添加的每张图片启用懒加载。
export default {
markdown: {
image: {
// 默认禁用图片懒加载
lazyLoading: true
}
}
}
显示行号
可以通过以下配置为每个代码块启用行号:
export default {
markdown: {
lineNumbers: true
}
}
查看 markdown
选项 获取更多信息。
可以在代码块中添加 :line-numbers
/ :no-line-numbers
标记来覆盖在配置中的设置。
还可以通过在 :line-numbers
之后添加 =
来自定义起始行号,例如 :line-numbers=2
表示代码块中的行号从 2 开始。
输入
```ts {1}
// 默认禁用行号
const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers {1}
// 启用行号
const line2 = 'This is line 2'
const line3 = 'This is line 3'
```
```ts:line-numbers=2 {1}
// 行号已启用,并从 2 开始
const line3 = 'This is line 3'
const line4 = 'This is line 4'
```
输出
// 默认禁用行号
const line2 = 'This is line 2'
const line3 = 'This is line 3'
// 启用行号
const line2 = 'This is line 2'
const line3 = 'This is line 3'
// 行号已启用,并从 2 开始
const line3 = 'This is line 3'
const line4 = 'This is line 4'
高级配置
VitePress 使用 markdown-it 作为 Markdown 渲染器。上面提到的很多扩展功能都是通过自定义插件实现的。可以使用 .vitepress/config.js
中的 markdown
选项来进一步自定义 markdown-it
实例。
import { defineConfig } from 'vitepress'
import markdownItAnchor from 'markdown-it-anchor'
import markdownItFoo from 'markdown-it-foo'
export default defineConfig({
markdown: {
// markdown-it-anchor 的选项
// https://github.com/valeriangalliat/markdown-it-anchor#usage
anchor: {
permalink: markdownItAnchor.permalink.headerLink()
},
// @mdit-vue/plugin-toc 的选项
// https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options
toc: { level: [1, 2] },
config: (md) => {
// 使用更多的 Markdown-it 插件!
md.use(markdownItFoo)
}
}
})
请查看配置参考:站点配置来获取完整的可配置属性列表。