ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Slidev Click Markers 教程:演讲者笔记高亮与自动滚动,从语法到源码实现

Slidev Click Markers 教程:演讲者笔记高亮与自动滚动,从语法到源码实现 Slidev Click Markers 教程:演讲者笔记高亮与自动滚动,从语法到源码实现【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidevClick Markers 是 Slidev(v0.48.0 起提供)的演讲者模式功能:在演讲者笔记中插入[click]标记,幻灯片每推进一次点击动画,对应段落就会在 Presenter 视图的笔记面板中被高亮并自动滚动到位。本文完整讲解该功能的标记语法、在仓库中的实际实现链路(构建期的标记解析、运行期的高亮与滚动),以及双击跳转等进阶交互,读完你既能直接在自己的幻灯片中使用它,也能理解slidev-note-click-mark背后的调用链与边界条件。解决什么问题对于信息密度高的幻灯片,演讲者笔记(HTML 注释)往往写得很长:开场铺垫、逐条要点、过渡语、提问预案……当幻灯片上运行着多级点击动画(v-click、v-clicks)时,口头讲解的节奏和笔记的阅读位置很容易脱节——讲到哪里了?该翻到笔记哪一段?Click Markers 就是为了解决定位问题:把笔记文本按第几次点击后应该讲到切成若干段,幻灯片点击进度每变化一次,Presenter 视图中的笔记面板就同步高亮当前段,并把视口平滑滚动到该段位置。功能入口文档见 docs/features/click-marker.md,它依赖笔记语法(docs/guide/syntax.md)和点击动画(docs/guide/animations.md)两个基础特性。标记语法与完整示例在幻灯片的笔记区(!-- --注释)中,在需要切换讲解节奏的行首放置[click]标记;想跨过若干次点击,则用[click:n]指定从上一个标记起再推进n次点击。官方文档给出的完整示例如下:!-- Content before the first click [click] This will be highlighted after the first click Also highlighted after the first click - [click] This list element will be highlighted after the second click [click:3] Last click (skip two clicks) --语义拆解:标记之间的内容构成一个段。段的首行(或列表项行)带标记时,该段归属于该标记对应的点击进度;第一个标记之前的内容(如Content before the first click)属于点击之前的初始段,初始状态下高亮;[click]等价于推进 1 次点击;[click:3]表示从上一个标记起再推进 3 次点击,即中间跨过的两次点击不改变笔记高亮,第 3 次点击时切到该段;高亮、滚动都只发生在 Presenter 视图,且只作用于当前幻灯片的笔记面板。构建期:标记如何被解析进 noteHTMLClick Markers 的标记 → 数据转换发生在 Slidev 的 Vite 虚拟模块加载阶段。核心逻辑在 loaders.ts 的renderNote函数中:function renderNote(text: string ) { if (withoutNotes) return let clickCount 0 // ... // Apply [click] marker let md text // replace [click] marker with span .replace(/\[click(?::(\d))?\]/gi, (_, count 1) { clickCount Number(count) return span classslidev-note-click-mark>const markers Array.from(noteDisplay.value.querySelectorAll(.${CLASS_MARKER})) as HTMLElement[] const markersMap new MapHTMLElement, number() const parentsMap new MapHTMLElement, [divider: HTMLElement | null, dividerClicks: number][]() // ...markersMap:每个span.slidev-note-click-mark元素 → 其data-clicks数值;parentsMap:沿 DOM 向上收集每个标记的所有祖先节点及其分割点(标记本身及其所属点击号),用于把高亮粒度提升到包含该标记的整段父级节点(段落、列表项、乃至整个子树);siblingsMap:把父节点的兄弟子节点(含纯文本节点,会先转成span以便统一处理)各自归属到最近一个分割点的点击号。随后processNote()返回一个按点击进度施效的闭包,watchEffect在clicksContext.current每次变化时调用它:watchEffect(() { const current props.clicksContext?.current ?? CLICKS_MAX applyHighlight.value?.(current) })闭包内部对三类元素打样式开关:段级:parent.classList.toggle(CLASS_FADE, enabled !clicks.some(([_, c]) c current))——当前点击号不在该父节点覆盖范围内时,整段加slidev-note-fade淡化;兄弟节点级:siblingsMap中的元素仅在其归属点击号等于current时保持全亮度;标记徽章:按相对关系打slidev-note-click-mark-past / -active / -next / -future四个状态类,分别对应已过去、当前、下一个、更远处。当autoScroll为真且某个标记的点击号恰好等于当前进度时,触发平滑滚动:if (enabled props.autoScroll clicks current) marker.scrollIntoView({ block: center, behavior: smooth })这里有一个值得注意的实现细节:从源码结构看,autoScrollprop 只在 NoteEditable.vue(开发模式下 Presenter 使用的可编辑笔记组件,传:auto-scroll!autoHeight)中被透传,而构建产物使用的 NoteStatic.vue 未传该 prop。也就是说,笔记高亮在所有环境下都生效,而自动滚动到当前段的行为主要面向 Presenter 交互场景;若你对生产环境的行为有精确预期,建议以 NoteStatic.vue 的实际渲染结果为准。另外,CLICKS_MAX(值为999999,定义于 constants.ts)在没有clicksContext时作为current的兜底值,意味着标记徽章会呈现未来状态的半透明外观,而withClicks计算属性要求同时存在clicksContext和标记 span 才会启用整套逻辑——这也是该功能仅在 Presenter 模式可用的底层原因之一。视觉呈现:淡化色与数字旗标标记与淡化的样式集中在 styles/index.css:.slidev-note-with-clicks .slidev-note-fade { color: #888888cc; } .dark .slidev-note-with-clicks .slidev-note-fade { color: #a1a1a1cc; } .slidev-note-click-mark { user-select: none; font-size: 0.7em; display: inline-flex; --uno: text-violet bg-violet/10 px1 font-mono rounded items-center border border-transparent; } .slidev-note-click-mark.slidev-note-click-mark-active { --uno: border border-violet; } .slidev-note-click-mark.slidev-note-click-mark-past { filter: saturate(0); opacity: 0.5; }即:未命中段落以半透明灰字淡化(深色模式取更浅的灰);标记本身渲染为一枚紫色小旗标,::before用内联 SVG 画旗杆旗面,::after用content: attr(data-clicks)显示该标记对应的点击编号;当前命中的旗标加紫色描边,过去/未来的分别降饱和或半透明。因此演讲者在笔记里看到的小数字,就是 loaders.ts 写进data-clicks的累计点击号。与点击系统的联动:双击跳帧NoteDisplay还暴露了两个事件:markerClick与markerDblclick。在processNote()中,每个标记被直接绑定了处理器:marker.ondblclick (e) { if (!enabled) return emit(markerDblclick, e, clicks) if (e.defaultPrevented) return props.clicksContext!.current clicks e.stopPropagation() e.stopImmediatePropagation() }也就是说,双击某个标记会直接把当前幻灯片的点击进度设定为该标记的点击号,幻灯片上的v-click元素随之跳到对应状态——这为演讲者回翻某一段要点提供了鼠标级操作,而不必依赖键盘逐步回溯。事件沿 NoteEditable.vue 向上冒泡,Presenter 页面(presenter.vue)通过useNav()提供的clicksContext驱动一切:它基于 useClicks.ts 的createClicksContextBase为每张幻灯片维护独立的点击上下文(含clicksStart、总点击数与clamp边界),笔记面板、主幻灯片、点击滑条(ClicksSlider)共享同一current值,因此标记高亮、幻灯片动画、底部点击滑条三者天然同步。配套能力与实战建议笔记编辑:开发模式下 Presenter 笔记面板可直接点击编辑,内容防抖 500ms 后写回幻灯片数据,Ctrl/Cmd S可立即保存,详见 NoteEditable.vue。标记写在笔记文本里即可,无需额外配置;frontmatter 起点:若幻灯片设置了clicksStart(经createClicksContextBase的clicksStart参数生效),点击号从该起点开始计数,标记的data-clicks仍是相对累计,建议标记编号从 0 号帧状态检查一遍;列表与嵌套:parentsMap/siblingsMap支持列表项与任意嵌套结构,- [click]写法让单个列表项成为独立高亮段(见文档示例第三段);构建产物:slidev build时会剥离raw/content/note原始文本以减小包体(loaders.ts),noteHTML依然保留,因此发布后的 Presenter 仍具备高亮能力;而--without-notes则彻底移除笔记。小结与源码索引Click Markers 用极低的书写成本([click]/[click:n])换来了讲到哪里、看哪里的演讲体验,其实现可概括为三步:构建期在 loaders.ts 把标记替换为带data-clicks的 span 并随noteHTML下发;运行期 NoteDisplay.vue 依据clicksContext.current做段级淡化、旗标状态切换与scrollIntoView平滑滚动;交互层支持双击标记直接跳帧。相关源码与文档入口:功能文档:docs/features/click-marker.md标记解析:packages/slidev/node/vite/loaders.ts#L389-L424高亮与滚动:packages/client/internals/NoteDisplay.vue笔记组件:packages/client/internals/NoteEditable.vue、packages/client/internals/NoteStatic.vue样式:packages/client/styles/index.css#L62-L108点击上下文:packages/client/composables/useClicks.ts、packages/client/pages/presenter.vue【免费下载链接】slidevPresentation Slides for Developers项目地址: https://gitcode.com/GitHub_Trending/sl/slidev创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表