ARTICLE DETAIL

资讯详情

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

mdBook 列表渲染全解析:从有序/无序列表到嵌套与起始序号

mdBook 列表渲染全解析:从有序/无序列表到嵌套与起始序号 开发工具文档【免费下载链接】mdBookCreate book from markdown files. Like Gitbook but implemented in Rust项目地址https://gitcode.com/gh_mirrors/md/mdBook点击查看免费下载mdBook 使用 Rust 生态成熟的pulldown-cmark解析器将 Markdown 章节转换为 HTML。本文以仓库测试套件中的 lists.md 测试文档为样本逐段剖析有序列表、无序列表、嵌套列表、起始序号与混合嵌套在 mdBook 中的实际渲染行为并结合源码级实现解析选项、事件流、树构建、HTML 序列化讲清每一个输出细节帮助你在编写书籍章节时写出可预期、可验证的列表语法。一、测试样本与验证方式lists.md是 mdBook 基础 Markdown 渲染测试的一部分位于tests/testsuite/markdown/basic_markdown/src/目录同一目录下还包含blank.md、blockquotes.md、code-blocks.md、inlines.md、links.md、images.md、html.md、svg.md等兄弟用例由SUMMARY.md汇总为名为basic_markdown的测试书。该测试书通过 tests/testsuite/markdown.rs 中的basic_markdown测试驱动#[test] fn basic_markdown() { BookTest::from_dir(markdown/basic_markdown).check_all_main_files(); }check_all_main_files()会把src/下每个章节经 mdBook 完整渲染得到的book/*.html与 expected 目录中的期望输出逐字节比对。也就是说本文讲解的每一条列表行为都有输入 Markdown → 期望 HTML的成对证据你可以直接在仓库中复现验证。二、渲染链路从 Markdown 到 HTML 的三步管线要理解列表为何渲染成这样先看清 mdBook 的 HTML 渲染流程。在 crates/mdbook-html/src/html/mod.rs 的模块文档中明确写明了三步走使用pulldown_cmark解析 Markdown产生事件Event流tree模块把这些事件转换为中间树结构TreeNode期间还会做增加标题锚点链接等变换serialize模块把树序列化为最终 HTML。核心入口是render_markdown它内部先调用build_tree生成树再交给serializepub(crate) fn render_markdown(text: str, options: HtmlRenderOptions_) - String { let tree build_tree(text, options); let mut output String::new(); serialize::serialize(tree, mut output); output }build_tree的关键在于构造解析器见 crates/mdbook-html/src/html/mod.rsfn build_tree(text: str, options: HtmlRenderOptions_) - TreeNode { let events new_cmark_parser(text, options.markdown_options); tree::MarkdownTreeBuilder::build(options, events) }而new_cmark_parser来自独立的 crates/mdbook-markdown/src/lib.rs它配置了 pulldown-cmark 的全部扩展选项pub fn new_cmark_parsertext(text: text str, options: MarkdownOptions) - Parsertext { let mut opts Options::empty(); opts.insert(Options::ENABLE_TABLES); opts.insert(Options::ENABLE_FOOTNOTES); opts.insert(Options::ENABLE_STRIKETHROUGH); opts.insert(Options::ENABLE_TASKLISTS); opts.insert(Options::ENABLE_HEADING_ATTRIBUTES); if options.smart_punctuation { opts.insert(Options::ENABLE_SMART_PUNCTUATION); } if options.definition_lists { opts.insert(Options::ENABLE_DEFINITION_LIST); } if options.admonitions { opts.insert(Options::ENABLE_GFM); } Parser::new_ext(text, opts) }列表本身是 CommonMark 规范的核心语法由pulldown_cmark基础能力保证上述扩展选项只影响表格、脚注、任务列表等外围特性。随后MarkdownTreeBuilder见 crates/mdbook-html/src/html/tree.rs将解析事件组装成中间树序列化阶段再把ol、ul、li等节点输出为 HTML。三、有序列表自动编号与嵌套lists.md的前两个用例验证有序列表ordered list的两种形态。3.1 普通有序列表输入1. A 2. Normal 3. Ordered 4. List期望输出expected/lists.htmlol liA/li liNormal/li liOrdered/li liList/li /ol注意输出中每个li之间没有额外的p包裹——这是 mdBook更准确地说是 pulldown-cmark对紧凑列表tight list的处理方式当列表项内容不含空行分隔的段落时直接输出裸文本节点不生成段落标签。这是与许多所见即所得编辑器不同的细节值得在比对渲染结果时留意。3.2 嵌套有序列表输入1. A 1. Nested 2. List 2. But 3. Still 4. Normal期望输出ol liA ol liNested/li liList/li /ol /li liBut/li liStill/li liNormal/li /ol这里展示了两个关键行为缩进即嵌套子列表项以 3 个空格缩进pulldown-cmark 依据缩进量CommonMark 要求列表嵌套缩进至少 2 个空格实际写法常为 4 或与父项内容对齐识别出这是一个嵌套ol嵌套不影响编号延续外层列表的计数从嵌套子列表结束后继续But、Still、Normal依次为第 2、3、4 项编号不受子列表插队干扰。四、起始序号尊重你写的第一个数字第三个用例是lists.md中最具特色的部分输入为7. Start list 7. with a different number.期望输出ol start7 liStart list/li liwith a different number./li /ol这是 CommonMark 的一个经典行为有序列表的起始序号取列表第一项的数字后续项的编号自动递增而非逐项采用你写下的字面数字。因此第二行即使也写7.渲染结果仍是第 8 项且整个列表元素被赋予start7属性。HTML 规范规定ol的start属性用于声明起始值浏览器据此从 7 开始显示编号。这个用例的存在意味着如果你在书籍中手写序号错乱例如从 3 开始、下一项写成 5mdBook 不会保留这种错位而是以首项为基准连续编号。想让列表从特定数字开始只需保证第一项的编号正确即可。五、无序列表-标记与嵌套5.1 普通无序列表输入- An - Unordered - Normal - List期望输出expected/lists.htmlul liAn/li liUnordered/li liNormal/li liList/li /ulpulldown-cmark 支持-、*、三种无序列表标记符这里统一使用-。与有序列表相同紧凑列表不产生p包裹。5.2 嵌套无序列表输入- Nested - Unordered - List期望输出ul liNested ul liUnordered/li /ul /li liList/li /ul子项- Unordered缩进 2 个空格被识别为内层ul且嵌套在liNested内部而非作为独立的兄弟列表输出——这正是列表嵌套与列表分段的差别只有缩进足够的行才会被并入上层列表项的子树。六、混合嵌套无序包有序最后一个用例验证列表类型可以自由混用- This 1. Is 2. Normal - ?!期望输出ul liThis ol liIs/li liNormal/li /ol /li li?!/li /ul无序列表项内部嵌入有序子列表marker-vs1.决定了内层是ul还是ol。这在编写操作步骤时非常实用外层用-组织一组相关任务内层用1./2.表达任务内部的执行次序。注意子列表依然没有p包裹整体保持紧凑输出。七、MDBook 列表渲染的行为总结综合六个用例可以归纳 mdBook 列表渲染的几条确定规则输入特征渲染结果证据1./2.逐项编号ol连续编号忽略字面数字错位lists.md首项从 7 开始ol start7后续自动 1lists.html子项缩进 24 空格嵌套ol/ul挂在父li内部lists.md-/*/标记ul无序列表lists.md无序内嵌有序外层ul、内层ollists.md紧凑列表无空行li内不产生p包裹全部期望输出八、列表之外的关联能力扩展列表语法掌握基础列表后mdBook 还提供了两个与列表相关的扩展它们同样由new_cmark_parser的选项开关控制在 crates/mdbook-core/src/config.rs 中有对应配置字段任务列表Task lists通过Options::ENABLE_TASKLISTS启用- [ ]/- [x]会被渲染为带复选框的列表项input disabled typecheckbox适合做待办清单定义列表Definition lists通过Options::ENABLE_DEFINITION_LIST启用术语独占一行、定义以:开头可生成dl词汇表结构具体语法参见 guide/src/format/markdown.md。两者默认开启smart_punctuation、definition_lists、admonitions在 crates/mdbook-markdown/src/lib.rs 中均为true并可通过book.toml中output.html的对应配置项关闭。你可以像下面这样显式控制[output.html] definition-lists true smart-punctuation true九、如何在本地复现验证若想亲自动手验证上述渲染结果可以按以下步骤操作仓库只读以下均为查看/构建/运行命令在仓库根目录构建 mdBookcargo build将tests/testsuite/markdown/basic_markdown目录复制到临时目录或直接基于该目录运行cargo run -- build tests/testsuite/markdown/basic_markdown构建输出默认写入book/目录注意这会与期望文件目录并存比对时以src/为输入即可用diff tests/testsuite/markdown/basic_markdown/expected/lists.html 输出目录/lists.html对照期望 HTML更省事的方式是直接运行完整测试cargo test --test testsuite basic_markdown对应 tests/testsuite/markdown.rs 中的basic_markdown用例它会自动完成渲染 → 与期望文件比对的全流程。十、小结通过lists.md这个精炼的测试样本我们完整验证了 mdBook 列表渲染的六种形态普通有序、嵌套有序、自定义起始序号、普通无序、嵌套无序、无序嵌套有序。其背后是从pulldown-cmark解析、MarkdownTreeBuilder建树到serialize输出的完整管线。对书籍作者而言核心要点只有三条编号以首项为准自动连续、缩进控制嵌套层级、紧凑列表不产生段落标签。掌握了这些你在 mdBook 中书写的每一个列表都能精确预知其在最终 HTML 中的样子。赞分享开发工具文档【免费下载链接】mdBookCreate book from markdown files. Like Gitbook but implemented in Rust项目地址https://gitcode.com/gh_mirrors/md/mdBook点击查看免费下载相关推荐marked 列表解析全解从 original 规格测试看无序、有序与嵌套列表的源码实现marked 列表解析全解从 original 规格测试看无序、有序与嵌套列表的源码实现 导读 本文以 marked 仓库中 test/specs/origi前端Markwon 有序列表起始序号解析从 ol-starts-with-5.md 测试用例看 start 编号的解析、传递与渲染Markwon 有序列表起始序号解析从 ol starts with 5.md 测试用例看 start 编号的解析、传递与渲染 Markwon 是一款基于 cUI组件移动开发Just the Docs 列表渲染指南无序列表、有序列表、任务列表与定义列表的完整实践Just the Docs 列表渲染指南无序列表、有序列表、任务列表与定义列表的完整实践 在 Just the Docs 文档主题中列表是组织文档信息最基础文档静态站点UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表