Slidev 绘图与标注实战指南:完整配置项详解与源码级实现原理 📅 发布时间:2026/9/8 20:32:53 👁 浏览次数: Slidev 绘图与标注实战指南完整配置项详解与源码级实现原理【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidev本文基于 Slidev 官方文档 docs/features/drawing.md 展开系统讲解 Slidev 内置绘图与标注功能的使用方式如何开启绘制工具栏、手写笔识别、绘图持久化、按场景禁用绘图以及跨实例同步等全部配置项并深入 packages/client/composables/useDrawings.ts、packages/slidev/node/integrations/drawings.ts 等源码解释配置背后的特征开关、状态同步链路与 SVG 落盘机制。读完本文你可以完全掌控 Slidev 的现场标注行为并理解其数据在浏览器与服务端之间的流转过程。功能概览基于 drauu 的绘图工具栏Slidev 内置了由 drauu 驱动的绘图与标注能力文档 frontmatter 中relates关联了 drauu 项目允许你在任意幻灯片上直接绘制、圈点、画箭头和几何图形。开启方式点击导航栏中的画笔carbon-pen图标打开绘图工具栏Presenter Mode演讲者模式中同样可用。你创建的绘图与标注会实时自动同步到所有实例。从源码看工具栏按钮的显示受特征开关与配置双重控制。NavControls.vue 中画笔按钮的渲染条件是IconButton v-if__SLIDEV_FEATURE_DRAWINGS__ (!configs.drawings.presenterOnly || isPresenter) classrelative :titledrawingEnabled ? Hide drawing toolbar : Show drawing toolbar :activedrawingEnabled clickdrawingEnabled !drawingEnabled即__SLIDEV_FEATURE_DRAWINGS__编译期开关为真且未开启presenterOnly或当前处于演讲者模式时才显示。工具栏组件 DrawingControls.vue 本身也在 Controls.vue 中按同样的条件动态加载presenterOnly: true时非演讲者窗口连工具栏都不会加载。工具栏提供了完整的绘制模式与画笔控制见 DrawingControls.vue六种模式钢笔stylus、直线line、箭头arrow、椭圆ellipse、矩形rectangle、擦除eraseLine七个预设画笔颜色定义在 useDrawings.ts 的brushColors中依次为#ff595e、#ffca3a、#8ac926、#1982c4、#6a4c93、#ffffff、#000000线宽滑杆1–15、撤销/重做、清空当前页、固定工具栏pin与关闭等按钮。绘制层由 DrawingLayer.vue 挂载一个全屏 SVG 承载drauu在onMounted时mount到该 SVG并监听缩放scale将coordinateScale设为1 / scale保证画布缩放时笔迹坐标不失真drawingEnabled为 false 时该层pointer-events-none不拦截导航操作。键盘快捷键useDrawings.ts 在绘图开启且未在输入时注册了完整的快捷键体系数字键 1–7 对应brushColors下标实现了对应色选择按键作用Ctrl/Cmd Z撤销Ctrl/Cmd Shift Z重做Esc关闭绘图模式L直线模式lineA箭头模式arrowS钢笔模式stylusR矩形模式rectangleE椭圆模式ellipseC清空当前页绘图1–7切换画笔颜色红/黄/绿/蓝/紫/白/黑被处理的按键会preventDefault()并stopPropagation()避免与翻页等全局快捷键冲突。手写笔设备使用输入类型自动识别在平板例如配备 Apple Pencil 的 iPad上使用手写笔时Slidev 会智能识别输入类型无需先开启绘图模式即可直接用笔在幻灯片上绘制同时手指或鼠标仍负责翻页导航。这一行为的实现位于 useDrawings.tsconst drauuOptions: DrauuOptions reactive({ brush, acceptsInputTypes: computed(() (drawingEnabled.value (!configs.drawings.presenterOnly || isPresenter.value)) ? undefined : [pen as const]), coordinateTransform: false, })关键在于acceptsInputTypes只有当“绘图模式开启 且非 presenterOnly 或处于演讲者模式”时才接受所有输入类型undefined表示不限否则仅接受pen手写笔指针事件。换言之未开启绘图时鼠标/触摸事件被忽略手写笔却可以直接落笔从而实现了“笔绘图、手指翻页”的分离。持久化绘图persist 配置与 SVG 落盘通过 frontmatter 配置可以将绘图保存为 SVG 文件并让它们出现在导出的 PDF 或托管站点中--- drawings: persist: true ---根据 packages/types/src/frontmatter.ts 中DrawingsOptions的定义persist的完整取值为boolean | string传true时写入默认的.slidev/drawings目录传字符串则相对入口文件所在目录解析为自定义目录见 drawings.ts 中 resolveDrawingsDir 的resolve(dirname(options.entry), options.data.config.drawings.persist)。persist的完整链路涉及三层编译期开关options.ts 将__SLIDEV_FEATURE_DRAWINGS_PERSIST__定义为!!options.data.config.drawings.persist。SlidesShow.vue 据此决定即使禁用了实时绘图也要加载DrawingLayer以便渲染已持久化的笔迹PrintSlideClick.vue 则在导出打印时为每一页点击帧叠加DrawingPreview这正是“绘图出现在导出 PDF 中”的原因。服务端读取开发服务器启动时serverRef.ts 调用loadDrawings(options)把磁盘上已有的绘图载入服务端共享状态loadDrawings 用fast-glob匹配目录下的*.svg以文件名数字部分作为页码键非数字文件名忽略并剥掉首尾的svg.../svg包裹行只保留内部路径数据。服务端写盘每当共享状态中的drawings键发生变化serverRef.ts 检查options.data.config.drawings.persist key drawings后调用writeDrawings。writeDrawings 会按canvasWidth与aspectRatio计算画布宽高生成svg width... height...头尾包裹后的完整 SVG逐页写入{页码}.svg。写入安全性isSafeDrawingKeywriteDrawings对每个键先做安全校验isSafeDrawingKey 要求键必须是纯数字/^\d$/且拼出的目标路径不能以..开头或为绝对路径从而拒绝路径穿越写入。该逻辑有专门测试覆盖见 drawings.test.ts接受3拒绝../../evil、a/b、空字符串与abc。禁用绘图enabled 与 presenterOnly完全禁用--- drawings: enabled: false ---仅开发模式可用--- drawings: enabled: dev ---根据 frontmatter.ts 的类型定义enabled取值为boolean | dev | build默认为true。其求值发生在编译期options.ts 中const matchMode (mode: string | boolean) mode true || mode options.mode // ... __SLIDEV_FEATURE_DRAWINGS__: matchMode(options.data.config.drawings.enabled),即enabled: true在所有模式生效enabled: dev只在开发模式生效enabled: build只在构建/导出生效enabled: false则任何模式都不生效。由于它是编译期常量false时工具栏按钮与绘图层会被直接裁剪而非运行时隐藏。仅演讲者模式可用--- drawings: presenterOnly: true ---如前文NavControls.vue条件所示presenterOnly: true时普通播放窗口的画笔按钮不再渲染同时 useDrawings.ts 中acceptsInputTypes的计算也会因此收窄普通窗口即使手写笔也不接受绘图输入仅保留pen类型且绘图开关默认关闭。绘图同步syncAll 与跨实例机制默认情况下Slidev 会在所有实例之间同步绘图。如果你正在与他人共享幻灯片可能希望禁用这种全量同步--- drawings: syncAll: false ---加上该配置后只有演讲者实例的绘图才会向其他实例同步。这一行为对应 useDrawings.ts 的一行核心逻辑const syncUp computed(() configs.drawings.syncAll || isPresenter.value)syncAll: true默认任何实例的改动都会patchDrawingState广播syncAll: false仅当当前窗口是演讲者isPresenter时才会把自己的笔迹写入共享状态观众窗口的涂鸦只留在本地。同步链路解析绘图状态的同步底座是 packages/client/state/drawings.ts// ts-expect-error - virtual module import serverDrawingState from server-reactive:drawings?diff // ... export const { init: initDrawingState, onPatch: onPatchDrawingState, onUpdate: onDrawingUpdate, patch: patchDrawingState, state: drawingState, } createSyncStateDrawingsState( serverDrawingState, serverDrawingState, __SLIDEV_FEATURE_DRAWINGS_PERSIST__, )server-reactive:drawings?diff是由 vite-plugin-vue-server-ref 提供的虚拟模块服务端维护Record页码, SVG 内部数据状态客户端拉取 diff 补丁。整条数据流为用户落笔 → drauu 触发changed事件 → useDrawings.ts 在!disableDump syncUp时drauu.dump()出序列化数据按当前页码patchDrawingState补丁经由 server-ref 通道广播到所有实例其他实例的 onPatchDrawingState 回调 用drauu.load(data)重绘并用disableDump标志防止“加载 → 再 dump → 再广播”的回环翻页时watch(currentSlideNo)触发 loadCanvas按页加载对应笔迹或清空画布。另外值得注意的本地状态drawingEnabled是否开启绘图、drawingPinned工具栏固定、brush颜色/线宽/模式都通过useLocalStorage持久化到浏览器键分别为slidev-drawing-enabled、slidev-drawing-pinned、slidev-drawing-brush刷新后画笔设置保持不变但绘图内容本身存在服务端共享状态及磁盘 SVG若开启了persist。配置速查表综合 frontmatter.ts 中 DrawingsOptions 定义 与 config.ts 中 ResolvedDrawingsOptions配置项类型默认值说明drawings.persistboolean \| stringfalse持久化到磁盘true用默认.slidev/drawings目录字符串可指定相对入口文件的自定义目录决定__SLIDEV_FEATURE_DRAWINGS_PERSIST__开关drawings.enabledboolean \| dev \| buildtrue是否启用绘图功能按模式匹配编译进__SLIDEV_FEATURE_DRAWINGS__开关drawings.presenterOnlybooleanfalse仅允许从演讲者模式绘制非演讲者窗口不显示画笔按钮drawings.syncAllbooleantrue是否在所有实例间同步绘图false时仅演讲者实例可同步给他人小结Slidev 的绘图与标注功能覆盖了“现场标注—跨实例同步—持久留痕—导出呈现”的完整闭环工具栏由编译期特征开关与 frontmatter 配置共同控制输入类型识别让手写笔设备开箱即用persist通过服务端loadDrawings/writeDrawings把笔迹以带画布尺寸的 SVG 文件按页落盘并有路径穿越防护测试背书而syncAll则决定了多实例场景下谁是唯一广播方。所有关键实现都可以从 useDrawings.ts、state/drawings.ts、integrations/drawings.ts 与 vite/serverRef.ts 中逐行对照本文验证。【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidev创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考