過去我在學術界做簡報通常都是用 LaTeX 當中的 Beamer 來做的,實際要展示的時候則搭配 Pympress 就可以有不錯的效果。然而,最近因為要在公司裡面講課的關係,會很頻繁地會需要製作簡報,而 LaTeX + Beamer 的語法寫起來終究是繁瑣了一點;我希望可以更快更簡單地就把簡報做好。於是我就在想,有沒有可以用 Markdown 的語法來製作簡報的系統,找了一找果然有、而且還不只一種,我最終選擇了 Slidev,因為它的功能真的很強,包括:
- 支援我上一篇提到的 shiki 語法標亮(其實我就是在研究 Markdown 簡報的過程中得知 shiki 的)、LaTeX 數學語法(透過 KaTeX)、Mermaid 圖表、Monaco 編輯器(可以即時展示程式碼編輯之類的)、以及 Iconify 圖示。
- 內建類似 Pympress 的播放功能,提供計時、畫筆、頁內筆記,而且還有 remote 模式可以在手機上遙控,也可以即時切換黑暗模式。
- 錄影功能,可以直接產生內嵌講者鏡頭的講演影片。
- 多種動畫效果,且因為核心是 Vue,任何 Vue 的套件都可以使用。
- 還算不小的社群提供有很多佈景主題(上面圖片所示的就是我參考 Beamer 的 Frankfurt 主題製作的 slidev-theme-frankfurt)。
- 可以輸出成 PDF 等格式,也可以建置成靜態的 SPA 網站來佈署在雲端。
- 有搭配的 VS Code 延伸模組。
Slidev 的官方文件 寫得也算清楚,所以我就不多重複教學了,單純分享幾個我使用下來的小心得。
內容目錄
使用小秘訣
- 對於 PNPM 使用者來說,Slidev 的套件設計使得它的 node_modules 目錄裡面必須扁平化才能正確運作,因此範本中自動建立的 .npmrc 檔案不可以刪掉。
- Slidev 的作者是 Anthony Fu 大,所以其預設的 CSS 框架也是他主導的 UnoCSS,算是小眾的框架,但對於熟悉 Tailwind 的人來說這個應該不難上手(我自己是 Bootstrap 派的,所以比較需要習慣)。
- Slidev 目前第一預設的語法標亮是透過 prism.js,所以記得要改成 shiki。選取 shiki 主題的方法則可參考這邊。
- 初次使用錄影功能的時候可能會出現使用者鏡頭視訊抓不到或是收音收不到的問題,此時重新啟動瀏覽器應該可以解決,但是總之記得錄影之前先測試一小段確定一下。
- 輸出成 PDF 的時候,記得要加上
--per-slide
選項,不然一些佈景主題輸出的樣式或內容會不太正確。另外 PDF 輸出預設是明亮模式,若要使用黑暗模式就要指定--dark
。
開發小秘訣
其實 Slidev 專案裡面的 .css 檔案內部都是吃 SCSS 語法的,但是偏偏又不能把副檔名改成 .scss(不然建置的時候會報錯),這點要注意。另外,裡面也可以使用 Tailwind 的 @apply
語法,但是 VS Code 可能會抗議,這個時候可以用如下的方式解決。在專案的 .vscode 目錄底下加入如下的 apply.json 檔案:
{
"version": 1.1,
"atDirectives": [
{
"name": "@apply",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#apply"
}
]
}
]
}
然後在 settings.json 當中加入這一段:
{
//...
"css.customData": [
".vscode/apply.json"
],
//...
}
就可以讓 VS Code 接受這個語法了。
另一方面,Slidev 在專案自訂的 Vue 元件當中會注入 $slidev
的上下文物件,不過這個物件並不是如同一般地被寫入到 app.config.globalProperties
當中,而是 Slidev 玩了一些黑箱手法寫入到各個元件裡頭的,其結果是,在 <script setup>
裡頭我們直接就可以用 $slidev
這個全域物件而無須匯入任何東西。不過這裡有一個小問題在於 Volar 的 TypeScript 語言服務可能會抗議,而解決的方法就是在專案裡頭加入像這樣的定義檔:
import type { UnwrapNestedRefs } from "vue";
import type { SlidevContext } from "@slidev/client/modules/context";
declare global {
const $slidev: UnwrapNestedRefs<SlidevContext>;
}
留言