如何增量地将 markdown 转换成 html?

203 天前
 ooo4

现在后台是流式输出 markdown 字符串,并且每次我也不断处理全量的 markdown 字符串,再使用MarkdownContent这个组件去渲染成 html

但这样会导致一个问题,就是在流式输出的过程中,由于会不断地执行这个MarkdownView组件,导致无法使用鼠标选中渲染后的文本,等下次 render 时,选中状态就又丢失了

有什么方案能够增量更新吗,不操作以前的 dom

// 大概就这样的逻辑
function App() {
  const [message, setMessage] = useState('')
  async function foo() {
    const reader = response.body?.getReader();
    const decoder = new TextDecoder();
    let result = "";
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      result += decoder.decode(value);
      setMessage(result);
    }
  }
  return <MarkdownContent source={message}></MarkdownContent>;
}

export const MarkdownContent = memo(({ source }: MarkdownContentProps) => {
  const html = useMemo(() => markdown.render(source ?? ""), [source])

  return (
    <article
      className='prose dark:prose-invert'
      style={{ maxWidth: "100%" }}
      dangerouslySetInnerHTML={{ __html: html }}
    />
  )
})
1229 次点击
所在节点    问与答
4 条回复
jifengg
203 天前
实时想的,不知道可行性:
根据 markdown 语法,对 markdown 进行最小切分。然后分别渲染后,append 到 dom 中。
由于 markdown 大部分语法也都是流式的,只要你正确切分,就能分块渲染。
当然也有一些不支持的,比如“文献引用”。但是影响不大。
FakerLeung
203 天前
全量解析,再 diff ?
sgiyy
203 天前
1. 维护一个数组,每次返回的 markdown 数据按规则(比如换行)切分后推入数组
2. 为了防止重复渲染,每个数组项维护一个唯一标识符( uid )。
3. 每个数组项渲染一个类似 MarkdownItemContent 的组件
my3157
202 天前
严谨一点的方法,做 tokenizer ,简单粗暴的方法,按行读取,用正则匹配需要成对出现的,比如 code block 这种,出现就就等结束符出现了再渲染

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1114622

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX