修仙的人 2025-09-28 09:01 重庆
点击关注公众号,技术干货及时达!
<script setup>// ... 省略其他配置;const md = MarkdownIt({ highlight,})const htmlText = computedAsync(async () => { return md.render(props.source)}, '')</script><template> <div v-html="htmlText"></div></template><!-- 使用 --><MarkdownRender :source="source"></MarkdownRender>v-html 是一个全量渲染的过程, 并且他仅仅渲染 html 字符串。这意味着,你不再享有 Vue DOM 更新时的 diff 算法优化, 同时也失去了使用 Vue 组件的权力。你所期望的调用方式以替换 Table 这个需求为例,你可以想象最直观的调用方式,就像:<!-- 这是一个简单用例, 实际实现考虑到扩展性, 会略有不同 --><MarkdownRender :source="source"> <template #table="{ data, columns }"> <MyTables :data="data" :columns="columns" /> </template></MarkdownRender>如果将数据收集到对应的插槽的参数中,那么我们就能轻松使用任意组件库,来替换原有标签.解析无论你使用何种 Markdown 工具 (markdown-it、marked、remark), 要想在渲染之前提取数据, 必然绕不开对 markdown 原文本的解析.这个过程需要封装在 MarkdownRender 中, 不被使用端感知.这里仅以 markdown-it 为例, 你可以在 markdown-it demo 查看解析结果// setupconst renderItems = computed(() => tokensToTree( md.parse(props.source, {})))// template<VkRenderer :source="renderItems"> <slot /></VkRenderer>一个完整的解析后的数据结构示例 -- h1 标签结构, 如下:{ "templateType": "GroupToken", "tag": "h1", "open": {}, // Markdown Tokon 省略 "close": {}, // Markdown Tokon 省略 "children": [ { "type": "inline", "tag": "", "attrs": null, "map": [ 0, 1 ], "nesting": 0, "level": 1, "children": [ { "type": "text", "tag": "", "attrs": null, "map": null, "nesting": 0, "level": 0, "children": null, "content": "标题一级", "markup": "", "info": "", "meta": null, "block": false, "hidden": false, "templateType": "text" } ], "content": "标题一级", "markup": "", "info": "", "meta": null, "block": true, "hidden": false, "templateType": "inline" } ]}而我们唯一要做的, 就是将解析后的结果交给用户, 让用户自定义渲染采用的组件.我想这就是全部! 是我们最终的目标!策略渲染如果你认真阅读, 解析章节, 那么你将发现const renderItems = computed(() => tokensToTree( md.parse(props.source, {}) )) // template <VkRenderer :source="renderItems"> <slot /> </VkRenderer>template 中的 VkRenderer 接收的source 正是解析后的树状结构.再回看解析后的 json 数据, 解析的过程中, 每个 item 都被添加了 templateType 字段.如果有一个组件能够匹配 templateType 字段, 来渲染内容. 那么我们将轻松实现「替换默认渲染」:为任何 Markdown 元素自定义渲染逻辑「增强交互性」:将静态内容转换为交互式组件「集成第三方库」:集成语法高亮、图表等功能「保持响应式」:利用 Vue 的响应式系统实现动态更新而你只需要将策略写在组件的默认插槽内, 使用起来就像:<script lang="ts" setup>import { VkMarkdown, VkRendererTemplate } from '@vunk/markdown'import { computed, ref } from 'vue'const source = `# Hello, Markdown!This is a simple example of using **Markdown** in a Vue component.`</script><template><VkMarkdown :source="source" > <VkRendererTemplate type="text"> <template #default={ raw }> {{ raw.content }} </template> </VkRendererTemplate> <VkRendererTemplate type="GroupToken"> <!-- 省略实现 --> </VkRendererTemplate> <!-- 省略 inline 实现 --></VkMarkdown></template>组件库所做的事很感谢你能看到这里, 如你所见 「解析」 和 「策略渲染」 就是 vunk-markdown 的核心.对于常见的渲染策略, 组件库中做了封装TemplatesDefault 用于渲染常规 Markdown 内容TemplateEcharts 用于 Echarts 图表渲染TemplateMermaid 用于 mermaid 流程图渲染AI编程资讯AI编码专区指南:
点击“阅读译文“了解详情~
