V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ooo4
V2EX  ›  问与答

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

  •  
  •   ooo4 · 35 天前 · 975 次点击
    这是一个创建于 35 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在后台是流式输出 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 }}
        />
      )
    })
    
    第 1 条附言  ·  35 天前

    img 看了看chatgpt的dom结构,应该是对markdown内容进行了二次编译,才做到了增量更新的

    第 2 条附言  ·  33 天前

    大概研究了下,写了个小工具,不过目前来说还很简陋

    https://linzhe141.github.io/markdown-stream/

    Live Demo

    4 条回复    2025-02-28 09:32:17 +08:00
    jifengg
        1
    jifengg  
       35 天前   ❤️ 1
    实时想的,不知道可行性:
    根据 markdown 语法,对 markdown 进行最小切分。然后分别渲染后,append 到 dom 中。
    由于 markdown 大部分语法也都是流式的,只要你正确切分,就能分块渲染。
    当然也有一些不支持的,比如“文献引用”。但是影响不大。
    FakerLeung
        2
    FakerLeung  
       35 天前
    全量解析,再 diff ?
    sgiyy
        3
    sgiyy  
       35 天前
    1. 维护一个数组,每次返回的 markdown 数据按规则(比如换行)切分后推入数组
    2. 为了防止重复渲染,每个数组项维护一个唯一标识符( uid )。
    3. 每个数组项渲染一个类似 MarkdownItemContent 的组件
    my3157
        4
    my3157  
       35 天前 via Android
    严谨一点的方法,做 tokenizer ,简单粗暴的方法,按行读取,用正则匹配需要成对出现的,比如 code block 这种,出现就就等结束符出现了再渲染
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2400 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 03:09 · PVG 11:09 · LAX 20:09 · JFK 23:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.