幻灯片 - markdown¶
使用 Markdown 一键生成精美幻灯片,先看演示。
选中幻灯片,试一试:
全屏模式 | 概览模式 | 演讲视图 | 暂停放映 |
---|---|---|---|
F 进入,ESC 退出 | O 或 ESC 进出 | S 进入 | B 或 . 进出 |
一、渲染框架¶
普通编辑器一般不支持制作幻灯片演示文稿,但可以借助开源项目轻松将 markdown 文件转化为精美幻灯片。
1. Reveal.js¶
reveal.js,一个流行的 HTML 幻灯片展示框架,能让任何人免费制作功能齐全且精美的演示文稿。
-
丰富的插件生态:Plugins, Tools and Hardware:
- 插件集:reveal.js-plugins,演示 Demo;
- 插件集:Martino's plugins;
-
扩展项目:
2. Slidev¶
Slidev (slide + dev),为开发者打造的极具灵活性和交互性的幻灯片制作工具。案例展示。
- 官方文档:为什么选 Slidev ?集成了 Vue 组件,还支持 Shiki Magic Move 和 TwoSlash 集成;
- 集成编辑:Slidev 附带了「内嵌编辑器」和 「VS Code 扩展」,也可以使用 在线编辑器;
3. Marp¶
Marp,使用 Markdown 编写演示文稿的生态系统。
- Framework:Marpit,独立于 Marp 的轻量级框架;
- CLI 界面:Marp CLI,将 Markdown 文件转换为静态 HTML / CSS、PDF、PowerPoint 文档和图像;
- 集成编辑:Marp for VS Code,VS Code 扩展;
- 推荐扩展:MarkSlides,基于 Marp 创建的幻灯片工具,支持使用 ChatGPT 等方式生成幻灯片,也可使用 在线编辑器 ;
4. 其他¶
- presenterm,基于终端的幻灯片工具,类似还有 slides;
- presenterm 基于 Rust 语言;
- slides 基于 Go 语言;
- moffee,基于 Python 的幻灯片制作工具;
- remark,一款在Web页面内用 Markdown 驱动的简单幻灯片工具,案例展示;
- 更多工具:
二、幻灯片输出¶
reveal.js 足够了。如果是开发者,不考虑复杂性和时间成本还可选择 Slidev。
- 使用编辑器,方便简单,但功能有限:
- Typora 支持导出幻灯片演示文稿。参考 使用 Pandoc 和 RevealJs 转换漂亮的演示文稿;
- MiaoYan 集成了 reveal.js,不需要导出直接在编辑器编写和预览;
- YankNote 内置插件库,可扩展 reveal.js 后直接使用;
- VS Code 也可以通过插件库扩展 reveal.js;
- 使用原生 reveal.js,通过 CLI 操作,功能最丰富,更好用。
三、使用 Reveal.js¶
推荐 MkSlides,拥有和 MkDocs 一样的极简文档结构和配置方式(可理解为 PPT 版的 MkDocs),建议通过 CLI 方式操作与使用。
1. 安装 MkSlides¶
参考 MkSlides 的 README 说明:
pip3 install mkslides
mkslides serve demo.md
mkslides serve -o docs/
mkslides build demo.md -d _slide
mkslides build docs/ -d _slide
2. 初始化¶
- 新建文档库,随意新建一个文件夹,比如 mkslides-proj;
- 在 mkslides-proj 中新建
docs
文件夹,用来存放 markdown 源文档; - 在 mkslides-proj 中新建
mkslides.yml
文件,用来配置所有文档的属性;
3. 基础语法¶
- 幻灯片分页:默认用分割线
---
,可自定义,还可配置垂直分页符; - 标记演讲备注:使用
Note:
,默认只在演讲视图下能看到演讲备注; - 设置幻灯片及元素属性:通过 HTML注解的方式。最大程度避免对 Markdown 语法的污染;
<!-- 举例:markdown语法 -->
文本靠右 <!-- .element: style="float: right; width: 40%" -->
文本靠左 <!-- .element: style="width: 40%" -->
用法参考 <!-- .element: class="fragment" -->
<!-- .slide: data-background="#5EAF9E" -->
4. 背景设置¶
用法参考:
<!-- .slide: data-background="#5EAF9E" -->
<!-- .slide: data-background="#F8CB9E" data-background-transition="zoom" -->
<!-- .slide: data-background-gradient="radial-gradient(#283b95, #17b2c3)" -->
<!-- .slide: data-background-image="assets/schoonmeersen.jpg" -->
<!-- .slide: data-background-video="xx.mp4" data-background-video-loop data-background-video-muted -->
<!-- .slide: data-background-iframe="https://revealjs.com/demo" data-background-interactive -->
通过 data-background
配置,支持 4 种不同类型:
类型 | 复合属性 |
---|---|
data-background-color | data-background-gradient |
data-background-image | data-background-size data-background-repeat data-background-opacity |
data-background-video | data-background-video-loop data-background-video-muted |
data-background-iframe | data-background-interactive |
5. 片段控制¶
用法参考:
1. 有序列表项 一 <!-- .element: class="fragment" -->
2. 有序列表项 二 <!-- .element: class="fragment" -->
3. 有序列表项 三 <!-- .element: class="fragment" -->
- 我第一最后出来 <!-- .element: class="fragment fade-down" data-fragment-index="3" -->
- 我第二先出来 <!-- .element: class="fragment highlight-current-yellow" data-fragment-index="1" -->
- 我第三再出来 <!-- .element: class="fragment fade-up" data-fragment-index="2" -->
内联元素¶
举例:Markdown 是一种轻量级的纯文本标记语言,用简单少量的符号对文字进行标注,从而实现 以最小的输入代价生成印刷级排版格式的文档。 它在 流畅的书写和印刷级阅读体验 之间找到了平衡, 让人只需专注内容而不是纠结排版。
常用的标记符号不超过十个,好记好用好效果。
用法参考:
<p>
<span class="fragment" data-fragment-index="0">Markdown 是一种轻量级的纯文本标记语言,用简单少量的符号对文字进行标注,从而实现</span>
<span class="fragment" data-fragment-index="1" style="color:red">以最小的输入代价生成印刷级排版格式的文档。</span>
<span class="fragment" data-fragment-index="2">它在</span>
<span class="fragment" data-fragment-index="3" style="color:red">流畅的书写和印刷级阅读体验</span>
<span class="fragment" data-fragment-index="3">之间找到了平衡,</span>
<span class="fragment" data-fragment-index="4">让人只需专注内容而不是纠结排版。</span>
</p>
<p class="fragment" data-fragment-index="5">常用的标记符号不超过十个,好记好用好效果。</p>
6. 动画补充¶
上一节 片段控制 就是动画设置,但还可以安装插件 reveal.js-appearance,补充更多动画效果,使用参考 demo-markdown。
<!-- .element: class="animate__bounceInLeft" -->
<!-- .element: class="animate__fadeInDown" data-split="words" -->
<!-- .element: class="animate__fadeInDown" data-split="letters" -->
<!-- .element: class="animate__fadeInDown" data-delay="200" -->
<!-- .element: class="animate__fadeInDown animate__slow" -->
<!-- .element: class="animate__fadeInDown animate__faster" data-split="words" data-delay="200" -->
<!-- .element: class="animate__fadeInUp animate__faster baseline" data-split="words" data-delay="80" data-container-delay="600" -->
<!-- .element: class="animate__flipInX demoimg" -->
<!-- .slide: data-autoappear="true" -->
7. 排版布局¶
详细教程,参考另一篇文档:Markdown 多列布局。
8. 动态代码¶
在代码块中用行号控制,直接在起始标记符 ``` 后面用中括号配行号方式设置。
- 行号高亮:
[3,8-10]
,第3行和第8-10行高亮; - 分步高亮:
[3-5|8-10|13-15]
,开始高亮 3-5 行,下一步 8-10,最后 13-15 行; - 行号偏移:
[30:]
,行号从 30 开始; - 组合使用:
[30: 1|2-4|5]
:
import { withTable, useTable } from 'table-render';
const Page = () => {
const { refresh } = useTable();
}
export default withTable(Page)
四、幻灯片操作¶
- 前后翻页:Space / Shift+Space,还可以使用方向键;
- 全屏模式:F 进入,ESC 退出;
- 概览模式:O 或 ESC 进出;
- 跳转页面:G 进入,输入页码,最后 Enter 确认;还可以用Shift+←/→ 跳转首/尾页;
- 暂停放映:B 或 . 进出;
- 演讲视图:S 进入,可在 markdown 源文中使用
Note:
标记演讲备注; - 绘图白板:D 进入,ESC 退出,需要先安装插件 tldreveal;
- 全文搜索:CTRL+Shift+F 进出,Enter 匹配下一项;
- 等比缩放:按住 Option (Alt) 同时鼠标单击需要缩放的位置;
- 帮助提示:Shift+? 进出;
- 菜单目录:M 或点击按钮进出,需要先安装插件 reveal.js-menu;
- 滚动视图:可通过URL激活,直接在URL后添加参数
?view=scroll
后回车; - PDF 输出:可通过URL激活,直接在URL后添加参数
?print-pdf
后回车,然后CTRL/CMD+P,利用系统打印功能另存为PDF;
五、配置与扩展¶
通过配置与扩展可实现幻灯片的各种自定义功能。MkSlides 有 2 种配置方式:
- 全局配置,使用
mkslides.yml
文件配置本文档库所有文档的 属性、插件、预处理; - 独立配置,在 markdown 文档中使用 YAML 前言来设定单个文档属性;
如果同时使用,则 YAML 前言会覆盖配置文件里同名项的值。一般用配置文件配好通用选项,个别特例再用 YAML 前言调整。选项参考 reveal.js config。
1. 独立配置¶
在 markdown 文档中使用 YAML Front Matter
来设定单个文档属性,内容参考:
title: Markdown 幻灯片
slides:
separator: '^\s*<!--h-->\s*$'
separator_vertical: '^\s*<!--v-->\s*$'
theme: solarized # league sky
revealjs:
transition: slide
navigationMode: linear
separator_notes: '^Notes?:'
2. 全局配置¶
使用一个 mkslides.yml
文件配置本文档库所有文档的 属性、插件、预处理,内容参考:
index:
title: Aaron - Slides
slides:
theme: sky
highlight_theme: monokai-sublime
separator: '^\s*<!--h-->\s*$'
separator_vertical: '^\s*<!--v-->\s*$'
separator_notes: '^Notes?:'
preprocess_script: preproc.py # 预处理脚本
revealjs:
width: 1280
height: 800
transition: slide
navigationMode: linear
menu:
titleSelector: 'h1, h2, h3'
hideMissingTitles: true
openButton: true
openSlideNumber: true
plugins:
- name: RevealMermaid
extra_javascript:
- ../plugin/reveal.js-mermaid-plugin/plugin/mermaid/mermaid.js
- name: RevealMenu
extra_javascript:
- ../plugin/reveal.js-menu/menu.js
- name: RevealPlantUML
extra_javascript:
- ../plugin/revealjs-plantuml/dist/plantuml.js
3. 插件安装¶
推荐这几个,更多插件可参考 前面插件集列表,安装方式参考每个插件的 README 说明:
- 菜单导航:
- reveal.js-menu,滑出式菜单;
- reveal.js-simplemenu,页眉页脚菜单;
- 图表与画图:
- tldreveal,绘图画图;
- reveal.js-mermaid-plugin,Mermaid 美人鱼图表插件;
- revealjs-plantuml,PlantUML 图表插件;
- 工具栏:
- reveal.js-toolbar,快速访问幻灯片的工具栏;
我采用了离线使用插件的方式,所以在根目录新建了 plugin 文件夹用来存放所有插件。
4. 预处理¶
可为 MkSlides 提供一个 Python 脚本,用来批处理文档格式的自定义调整。
- 例如,让标题自动创建新幻灯片(省去了手动输入分页符的操作),可创建脚本
preproc.py
,将其路径配置在mkslides.yml
中:
def preprocess(markdown_text: str) -> str:
lines = markdown_text.split('\n')
result = []
first_heading_found = False
for index, line in enumerate(lines):
stripped = line.lstrip()
if stripped.startswith('#'):
if first_heading_found:
result.append('\n<!--h-->\n' if len(stripped.split()[0]) <= 2 else '\n<!--v-->\n')
else:
first_heading_found = True
result.append(line)
return '\n'.join(result)
5. 目录树¶
.
├── docs
│ ├── slide.md
│ └── xxx.md
├── plugin # 离线插件目录
│ ├── reveal.js-menu
│ │ └──menu.js
│ └── reveal.js-mermaid
│ └──mermaid.js
├── preproc.py
└── mkslides.yml
六、AI 加持¶
可以用 AI 自动生成代码,比如上面的 预处理 脚本。
1. Prompt¶
写一段解析 markdown 文本的代码,要求如下:
1. 在一级标题(#)和二级标题(##)前一行添加分隔符 -h-,对于其他级别的标题,添加 -v-;
2. 忽略第一次的标题的添加动作;
3. 要考虑标题前有空格的情况;
4. 用 JavaScript 或 Python 实现;
Write a piece of code that parses markdown text with the following requirements:
1. Add the separator -h- to the line before the first-level heading (#) and the second-level heading (##), and -v- for the headings at other levels;
2. Ignore the first action of adding titles;
3. Consider the case where there is a space before the title;
4. Implemented in JavaScript or Python;
2. Claude 解析¶
Claude,我只能说:🐮👍。需求理解、 代码质量、代码注释、结果预演等样样到位,甚至连示范输出都考虑了各种情况。
需求理解¶
1. Takes a markdown text as input and processes it line by line
2. Identifies heading lines by checking for '#' symbols at the start (after removing leading spaces)
3. Adds the appropriate separator:
4. '-h-' for level 1 and 2 headings (# and ##)
5. '-v-' for all other heading levels
6. Ignores the first heading encountered (no separator added)
7. Handles cases where there are spaces before the heading markers
8. Preserves the original formatting and spacing
结果预演¶
Python实现¶
Claude 3.5 Sonnet
:
def preprocess(markdown_text: str) -> str:
lines = markdown_text.split('\n')
result = []
first_heading_found = False
for index, line in enumerate(lines):
stripped = line.lstrip()
if stripped.startswith('#'):
if first_heading_found:
result.append('\n<!--h-->\n' if len(stripped.split()[0]) <= 2 else '\n<!--v-->\n')
else:
first_heading_found = True
result.append(line)
return '\n'.join(result)
3. ChatGPT 解析¶
中规中矩,代码都可以使用。
Python 实现¶
ChatGPT 4o
:
def parse_markdown(md_text: str) -> str:
lines = md_text.split("\n")
result = []
first_title_found = False # Flag to ignore the first heading
for line in lines:
stripped_line = line.lstrip() # Remove leading spaces for title detection
if stripped_line.startswith("#"):
if not first_title_found:
first_title_found = True # Skip adding separator for the first title
else:
if stripped_line.startswith("##"):
result.append("\n<!--h-->\n") # Separator for ## headings
elif stripped_line.startswith("#"):
result.append("\n<!--h-->\n") # Separator for # headings
else:
result.append("\n<!--v-->\n") # Separator for other headings
result.append(line) # Add the original line
return "\n".join(result)
七、示范 Demo¶
完整示范见 md-slideshow。
加载评论中...