Slidev Markdown 语法全景拆解:以 VS Code 扩展的 slidev.example.md 与语法实现为纲
【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidev
本篇以 Slidev 仓库内 VS Code 扩展的语法示例文件 slidev.example.md 为主线,逐段拆解其覆盖的每类演讲稿 Markdown 语法——从 YAML frontmatter、---幻灯片分隔、src幻灯片导入,到行高亮与点击步进、twoslash 类型检查、monaco-run 在线运行、Magic Move 与 KaTeX 数学公式。文中同步对照同目录下的 TextMate 语法文件与 ESLint 配置,说明这些写法在编辑器高亮与格式化层面是如何被识别与验证的,帮助读者把"看得见的语法效果"和"底层的解析规则"一次对齐。
这份示例文件在仓库里扮演什么角色
先看它在仓库中的物理位置与上下文。该文件位于 VS Code 扩展包的语法资源目录下:
- 示例本体:packages/vscode/syntaxes/slidev.example.md
- 配套语法声明:packages/vscode/syntaxes/slidev.tmLanguage.json
- Markdown 内代码块注入语法:packages/vscode/syntaxes/codeblock.json
- 代码块语法补齐脚本:packages/vscode/syntaxes/codeblock-patch.ts
它并不是"写给观众看"的演讲稿,而是一个语法面(syntax surface)的活体标本。两层证据可以确认这一点:
其一,它是 Slidev 专用 Markdown 格式化的校验样本。仓库根目录的 eslint.config.js 中配置了 antfu ESLint 预设的slidevformatter,并明确把**/slides.md、**/template.md、**/example.md以及packages/vscode/syntaxes/slidev.example.md一起纳入处理范围。也就是说,这份文件会持续经过 Slidev 感知的 Markdown 格式化/校验,凡是文件中出现的语法形态都必须能被正确解析并保持稳定输出,任何破坏语法的改动都会在 CI/lint 中暴露。
其二,它的每种写法都能在同目录的 TextMate 语法规则中找到对应的 token 化规则(详见后文各节),本质上充当了语法高亮器的覆盖样例。
配套目录下还有一个 pages.md,内容只有两个小标题幻灯片(# 1/# 2),正是为了配合示例中src: ./pages.md的幻灯片导入语法而存在。
因此,读懂这份文件 = 读懂 Slidev 面向用户开放的绝大部分 Markdown 扩展语法。下面按语法类别逐层展开。
逐字通读:示例文件的完整原文
先把文件原文完整陈列,后续所有章节都以它为讨论对象:
--- foo: a bar: 1 --- # Example Slides **Hello** World [](./a) ```ts {a} console.log('Hello World') ``` --- # Import Snippets --- src: ./pages.md --- --- # Vue Component <div title="hi" /> <Comp :x="a" /> <script setup lang="ts"> import { ref } from 'vue' let a = ref(1) </script> --- layout: center text: 1 --- # Code block ```ts {1,2|3} const a = 1 ``` ```ts twoslash const a = 1 ``` ```vue {monaco-run}{showOutputAt: '+1'} <template> <div /> </template> ``` ```ts {monaco-run}{showOutputAt: '+1'} twoslash const a = 1 const b = 2 ``` $$ \lambda = 1 $$ --- layout: center text: 2 --- # Magic Move ````md magic-move ```ts const a = 1 ``` ```ts const a = 1 const b = 2 const c = 3 ``` ````从结构上可以立刻观察到 Slidev 与普通 Markdown 的三个关键差异:
- 用
---横向分隔线把整份 Markdown切分成多个幻灯片块; - 支持顶层 frontmatter(文件开头的
---包裹块)与每页 frontmatter(紧跟分隔符之后的---包裹块)两种 YAML 头部; - 围栏代码块的第一行(info string)被扩展为携带语言、注解与 JSON 选项的复合格式。
下面逐一拆解。
frontmatter 家族:文件级配置与每页级配置
示例开头的两行 YAML 就构成顶层 frontmatter(又称 headmatter):
--- foo: a bar: 1 ---这是整份演讲稿的"全局配置区",Slidev 大量内置与用户自定义配置都写在这里。语法层面,slidev.tmLanguage.json 中名为slide-frontmatter的规则会捕获---包裹区域,将内容标记为meta.embedded.block.yaml并内嵌source.yaml,因此你在编辑器里看到 frontmatter 里的键值能被当作 YAML 着色;packages/vscode/package.json 的 grammar 声明里也定义了source.yaml与source.ts的内嵌语言映射。
关于 frontmatter 的更多细节(配置项含义、多入口 frontmatter 合并等),可进一步阅读仓库文档:
- 每页 frontmatter 的用法与约束:docs/features/block-frontmatter.md
- 各层 frontmatter 的合并顺序:docs/features/frontmatter-merging.md
- 关键配置速查:docs/guide/syntax.md
每页 frontmatter出现在示例的"Code block"与"Magic Move"两页前:
--- layout: center text: 1 --- --- layout: center text: 2 ---它们紧跟幻灯片分隔符、位于该页正文之前,用来覆盖本页的布局(layout: center对应内置居中布局)以及自定义元数据(这里的text: 1、text: 2是作者自定义键,仅供页面自身或自定义布局消费,Slidev 本身没有text配置,示例用它来检验任意键能否通过解析)。
值得一提的边界:这些 frontmatter 块之间的正文默认会在 Markdown 中渲染为水平线,但 Slidev 的解析层会把作为幻灯片分隔符的---与普通 Markdown 分隔线区分对待,这正是其解析器(见 packages/parser/src 的实现)的核心职责之一。
幻灯片分隔与单行相对链接
示例里最简单的语法反而是最核心的:一行独立的---就是幻灯片分隔符。每个分隔符之间的内容构成一张幻灯片:
# Example Slides **Hello** World [](./a) ...代码块...注意正文里的[](./a):这是一条空文本的 Markdown 相对链接。它在高亮语法上走标准 Markdown 链接解析路径,用于验证链接/图片语法的兼容性(即"普通 Markdown 特性不被破坏")。在实际演讲中,相对资源(图片、附加页、被引用的 Markdown 文件)就是通过这类路径来组织。
用src导入其他 Markdown 片段或整份幻灯片
示例中出现了单独的每页 frontmatter:
--- src: ./pages.md ---src是 Slidev 提供的"引用式导入":它把另一个 Markdown 文件中的幻灯片合并进当前演讲稿。这也是示例目录里专门准备了 pages.md(只有两个小标题页)的原因——它是src相对导入的目标样例。
实际工程里src有更细的玩法,例如用src配合行范围选择或#标题定位来按需引入内容片段。可参考:
- 官方功能文档:docs/features/importing-slides.md
- 关于
<<<代码片段导入(与本语法不同但常被并列讨论):语法规则见 slidev.tmLanguage.json 中的import-snippet规则,功能文档见 docs/features/import-snippet.md
从语法实现上看,src键在 per-slide frontmatter 中被统一解析,说明"文件级合并"发生在 Markdown 文本真正进入渲染管线之前——这属于 parser 包(packages/parser/src/index.ts 等)的职责。
代码块语法(一):行高亮、行号范围与点击步进
示例里有一段被缩进的围栏代码块:
```ts {1,2|3} const a = 1去掉缩进后其本质是: ```ts ```ts {1,2|3} const a = 1它演示了 Slidev 代码块属性语法中最常用的一类——**花括号里的范围 + 点击步进**: - 不带 `|`:`{1}`、`{1-3}`、`{*}`、`{all}` 等表示一次性高亮/展示的行范围; - 带 `|`:`{1,2|3}` 表示第一次点击高亮第 1、2 行,第二次点击再高亮第 3 行,实现**逐段(click-by-click)**揭示代码; - 多段可继续延长,如 `{1|2|3}` 表示三次点击逐步高亮。 编辑器侧,[codeblock.json](https://link.gitcode.com/i/a7ce02687157f7e88bba1df34018c09b#L5-L56) 的注入规则会把代码块首行从 `{` 到 `}` 的部分整体标记为 `meta.code_block_attrs.slidev`,其中的范围内容再交由 `range-with-steps` 与 `range` 规则细分;而 [slidev.tmLanguage.json](https://link.gitcode.com/i/248cebd8fca41005c0acc9ba2fbbab17#L49-L74) 里 `range` 的正则是 `(\d+|\*|all)([,-])?`——即支持数字、`*`、`all` 三种取值与逗号/连字符的组合。这解释了为什么 `{1,2|3}` 会被精确高亮为范围语义。 示例第一屏里还有一个看似"奇怪"的用例 `{a}`:`a` 并不是合法范围值,也不会命中 `range` 的内层规则。它属于语法压力测试——用于确认高亮器与格式化器在遇到**任意花括号内容**时不会解析崩溃、只把它当作待定区域容错处理。写作实际幻灯片时,请使用 `{1,2|3}` 这类合法范围。 功能细节可参考: - 行号显隐:[docs/features/code-block-line-numbers.md](https://link.gitcode.com/i/d9cde14ac89e3d2d2af18ff098f17e91) - 行高亮与点击步进的完整语法:[docs/features/line-highlighting.md](https://link.gitcode.com/i/d77fd560601dce9ad4a20782b47b8553) - 点击步进在不同场景下的统一语义:[docs/features/click-marker.md](https://link.gitcode.com/i/4e581067b7274658b8d000bd32d7ce99) ## 代码块语法(二):twoslash 静态类型检查 示例中独立出现了两种 twoslash 用法: ```ts ```ts twoslash const a = 1以及后面与 monaco-run 叠加使用的写法(见下节)。只要在语言标签后追加 `twoslash`,Slidev 就会在本地对代码块做 TypeScript 类型检查,并把类型查询结果(如悬停提示、诊断、内联类型标注)直接渲染在幻灯片上——适合讲解类型推导、泛型、重载等静态语义内容的场景。 语法层面对应的证据非常直白:[codeblock.json](https://link.gitcode.com/i/a7ce02687157f7e88bba1df34018c09b#L6-L9) 第一条规则就是把代码块首行中的字面量 `twoslash` 着色为 `keyword.twoslash.slidev`;示例中 `{monaco-run}... twoslash` 这种"注解 + 关键字并列"的形态,也由 codeblock 语法的剩余行(对行尾 `.twoslash` 的捕获)覆盖。 twoslash 的完整能力与配置见 [docs/features/twoslash.md](https://link.gitcode.com/i/a427320fed7744fc13b59ba371ae2499);其渲染样式(内联标注配色等)可在 [docs/custom/config-highlighter.md](https://link.gitcode.com/i/6b9661144730dc19ff6d2d104fcaeafb) 了解。 ## 代码块语法(三):monaco-run 让代码"能运行" 示例里把 monaco-run 用了两次: ```vue ```vue {monaco-run}{showOutputAt: '+1'} <template> <div /> </template>```ts ```ts {monaco-run}{showOutputAt: '+1'} twoslash const a = 1 const b = 2拆开看有三个组成部分: 1. **语言标签**:`vue` / `ts`,决定代码类型与运行环境; 2. **`{monaco-run}`**:第一对花括号中的关键字,告诉 Slidev 把这段代码交给内嵌 Monaco 编辑器"运行"而不是只做静态展示; 3. **`{showOutputAt: '+1'}`**:第二对花括号是 **JSON/TS 风格的对象字面量**,用于传入运行选项。这里的 `showOutputAt: '+1'` 表示把运行输出的展示推迟到相对的下一个点击步进(`+1`)之后,方便先讲代码、再揭晓结果。 同时它还可以与 twoslash 叠加(第二例),实现"既做类型检查、又能一键运行"。 语法实现上,[slidev.tmLanguage.json](https://link.gitcode.com/i/248cebd8fca41005c0acc9ba2fbbab17#L75-L82) 的 `monaco-type` 规则用正则 `monaco(-(run|diff))?` 匹配 `monaco` / `monaco-run` / `monaco-diff` 等关键字;[codeblock.json](https://link.gitcode.com/i/a7ce02687157f7e88bba1df34018c09b#L45-L50) 则把第二对花括号的内容声明为 `meta.embedded.block.code_block_options.ts` 并直接内嵌 `source.ts#object-literal` 语法——也就是说,**编辑器把这段选项按 TypeScript 对象字面量来着色**,这正是它支持键值对、引号、数字的语法来源。 相关扩展阅读: - Monaco 代码编辑器静态渲染:[docs/features/monaco-editor.md](https://link.gitcode.com/i/dfd45610f35065c55c44aa041ac7e839) - 代码运行模式与 `showOutputAt` 等选项语义:[docs/features/monaco-run.md](https://link.gitcode.com/i/be729317ce433a12cdfcb58a054bef0b) - 可写回文件的 `monaco-write` 模式:[docs/features/monaco-write.md](https://link.gitcode.com/i/7fe018712b9f7eab1bad80c2e916db1a) ## KaTeX 数学公式块 示例包含一个块级公式: ```tex $$ \lambda = 1 $$一对$$包裹的内容会走 LaTeX/KaTeX 渲染,行内公式则用单$...$。幻灯片排版数学推导、算法复杂度、物理公式等场景都依赖它。更多可阅读 docs/features/latex.md;语法细节(如 KaTeX 配置)见 docs/custom/config-katex.md。仓库内还提供了 KaTeX 专属样式文件 packages/client/styles/katex.css,说明数学渲染是客户端内置能力。
Vue 组件与<script setup>直接内联
Slidev 的 Markdown 本身可写 Vue SFC 片段,示例里的这一屏同时展示了标签元素与脚本:
<div title="hi" /> <Comp :x="a" /> <script setup lang="ts"> import { ref } from 'vue' let a = ref(1) </script>含义是:
- 普通 HTML 标签(
<div title="hi" />)会被当作 Vue 模板处理; - 自定义组件标签(
<Comp :x="a" />)会解析为对组件Comp的引用——你可以把组件文件放进components/目录实现零注册导入(vite插件层面的自动注册见 packages/slidev/node/vite/components.ts); <script setup lang="ts">是在单页内定义响应式状态与逻辑的官方推荐写法,示例中以ref(1)为例。
也就是说,Vue 的组合式能力被原生带进了每一页幻灯片里。这与文档 docs/guide/component.md、docs/guide/ui.md 描述的内置组件体系是一脉相承的。
Magic Move:代码块的渐变过渡
示例的最后一屏使用了一个"四层反引号"的围栏结构:
````md magic-move ```ts const a = 1const a = 1 const b = 2 const c = 3``` 这里把 `magic-move` 写在 `md` 语言标签之后,代码块内部再嵌套普通的三反引号代码块。Slidev 的 Magic Move(承袭自 Shiki Magic Move 的思想)会对比两个"帧"的代码差异,在翻页时对**新增/删除/改动行做平滑位移与渐隐动画**,非常适合演示代码如何一步步生长演化。 可参考文档 [docs/features/shiki-magic-move.md](https://link.gitcode.com/i/62a946967caacd0462328bde9a269c13);仓库内的相关解析逻辑位于语法层的 magic-move 处理中([packages/slidev/node/syntax/codeblock/magic-move.ts](https://link.gitcode.com/i/93b0b441a6fec59df7e43327688093a3) 与其测试 [magic-move.test.ts](https://link.gitcode.com/i/b1a96fa564bc0d86a83a9962e40b6c2e)),如果你关心"四反引号结构是如何被识别出来的",那是它的核心职责。 ## 把这些语法装进 VS Code:扩展侧的全景 整份示例所展示的语法形态,最终由 VS Code 扩展的多条 TextMate 语法注入到普通 Markdown 上生效(contributions 见 [packages/vscode/package.json](https://link.gitcode.com/i/c1701391640bcd85633ce20e454d4f29)): - [slidev.tmLanguage.json](https://link.gitcode.com/i/248cebd8fca41005c0acc9ba2fbbab17):作用域名 `source.slidev`,负责 frontmatter、`<<<` 片段导入、monaco 关键字、范围语法等 Slidev 特有结构; - [codeblock.json](https://link.gitcode.com/i/a7ce02687157f7e88bba1df34018c09b):以 `inject-to-markdown.codeblock.slidev` 注入 Markdown 围栏代码块,负责 `twoslash` 关键字、花括号属性与 TS 选项对象; - [codeblock-patch.ts](https://link.gitcode.com/i/a4178ab09d5176710575c6bf1babc1ac):运行时复制 Markdown 内置的各类 `fenced_code_block_*` 规则、清空其默认属性解析,改由 Slidev 规则接管,从而避免高亮冲突; - 内嵌语言映射在 [package.json](https://link.gitcode.com/i/1e370899aee4abd36821f6bc9ebbd4fd) 与 [codeblock-patch.ts](https://link.gitcode.com/i/a4178ab09d5176710575c6bf1babc1ac) 中把 YAML、TypeScript、HTML 及大量代码语言挂到对应区域上,保证 frontmatter 与代码块内部依然获得原生语言的着色体验。 也就是说,示例文件里每一种写法,都能在扩展启动后获得"结构着色 + 内嵌语言着色"的正确反馈。若要亲自验证,安装该扩展并打开仓库中的 [slidev.example.md](https://link.gitcode.com/i/a9da182a7648f5de6cddb436cbbc1b21) 即可观察到 frontmatter(YAML 着色)、`monaco`/`twoslash`(关键字着色)、代码块属性花括号等不同色调——这份文件天然就是验证安装是否生效的"高亮试金石"。 ## 如何把示例变成你自己的演讲稿 想把这些语法真正跑起来,做法很简单:把 [slidev.example.md](https://link.gitcode.com/i/a9da182a7648f5de6cddb436cbbc1b21) 的内容复制到你自己项目中的 `slides.md`(并连同其同目录的 [pages.md](https://link.gitcode.com/i/09578aea214d8dc8abe66489e65a322f) 一起复制,因为 `src: ./pages.md` 指向它),然后启动 Slidev 开发服务器即可逐页浏览效果;若使用 VS Code 扩展,则可在侧边面板直接预览与跳页。仓库自带的起步模板 [demo/starter](https://link.gitcode.com/i/a46a29c4af94ed3314a9d950c0ae6676) 与 [demo/composable-vue](https://link.gitcode.com/i/cad07a446fd9aa98f547cef1b0181e3d) 也是体验语法与组件写法的现成样例。 ## 小结:一张语法清单 把示例文件覆盖的全部语法收拢成一张速查表: | 语法形态 | 示例 | 作用 | 仓库佐证 | | --- | --- | --- | --- | | 顶层 frontmatter | `---\nfoo: a\n---` | 全局配置 | [slidev.tmLanguage.json](https://link.gitcode.com/i/248cebd8fca41005c0acc9ba2fbbab17#L83-L110) | | 幻灯片分隔符 | `---` | 切分幻灯片块 | parser 解析层 | | 每页 frontmatter | `layout: center` | 单页布局/元数据 | 同上 | | 幻灯片导入 | `src: ./pages.md` | 合并外部 Markdown | [docs/features/importing-slides.md](https://link.gitcode.com/i/18b8cd2bfef68c62c3d347cbb5ce4c77) | | 范围/点击步进 | `{1,2\|3}` | 逐步高亮行 | [codeblock.json](https://link.gitcode.com/i/a7ce02687157f7e88bba1df34018c09b#L11-L54) | | twoslash | `ts twoslash` | 静态类型检查 | [docs/features/twoslash.md](https://link.gitcode.com/i/a427320fed7744fc13b59ba371ae2499) | | monaco-run | `{monaco-run}{showOutputAt:'+1'}` | 在线运行代码 | [docs/features/monaco-run.md](https://link.gitcode.com/i/be729317ce433a12cdfcb58a054bef0b) | | KaTeX 公式 | `$$\lambda=1$$` | 数学公式渲染 | [docs/features/latex.md](https://link.gitcode.com/i/601029effe559e471fb99fcb2d118cc4) | | Vue 内联 | `<script setup lang="ts">` | 页面级逻辑与组件 | [docs/guide/component.md](https://link.gitcode.com/i/4d4a59cd5ab6e8715fe7c1daa098f9f9) | | Magic Move | ```` ```md magic-move ```` | 代码帧间平滑过渡 | [docs/features/shiki-magic-move.md](https://link.gitcode.com/i/62a946967caacd0462328bde9a269c13) | 正如前文所证明的:这份"例子里没有一句废话"的文件,既是语法高亮与 Slidev 格式化器持续回归测试的夹具,也是开发者快速对照学习幻灯片 Markdown 各种写法的浓缩教材。将其通读一遍、对照本文章节逐屏验证,就能对 Slidev 的核心内容语法形成完整且可运行的心智模型。【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidev
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考