打造一个支持流式输出的 Vue Markdown 渲染组件

打造一个支持流式输出的 Vue Markdown 渲染组件

在构建类似 ChatGPT 的对话交互界面时,我发现 Vue 社区缺乏一个原生支持流式 Markdown 渲染 的方案。而在 React 社区,很多人会使用 react-markdown 来实现类似需求。

react-markdown 的底层原理其实不复杂:它将 Markdown 文本解析为 markdown AST,再转换为 HTML AST,最后通过 React 的虚拟 DOM 机制将其渲染为 React 元素。这种方式充分利用了 React 的 Reconciliation 特性,在性能上表现非常优秀。

受此启发,我参考其实现方式,开发了一个 Vue 版本的流式 Markdown 渲染组件。

大概功能

  • 流式输出支持:模拟大语言模型逐字输出的效果,支持按粒度拆分内容逐步渲染
  • 高亮美观 :集成 shiki 实现语法高亮,且也支持流式处理
  • 性能优异 :基于 Vue 的虚拟 DOM 实现渐进渲染,性能显著优于直接使用 v-htmlmarkdown-it

安装方式

bash 复制代码
npm install vue-mdr

快速上手

1. 根据拆分的chunk,添加自定义的动画

css 复制代码
/* animation.css */
.vue-markdown-wrapper > *,
.vue-markdown-wrapper .text-segmenter,
.vue-markdown-wrapper .shiki-stream span {
  animation: fade-in 0.5s ease-in-out;
}

@keyframes fade-in {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

2. 使用示例

vue 复制代码
<script setup>
import { VueMarkdownRenderer } from "vue-mdr";
import { ref, onMounted } from "vue";
import "./animation.css";

// 创建模拟流式输出的函数
function createStream(text, chunkSize = 10, delay = 50) {
  let position = 0;
  return new ReadableStream({
    async pull(controller) {
      if (position >= text.length) {
        controller.close();
        return;
      }
      const chunk = text.slice(position, position + chunkSize);
      position += chunkSize;
      controller.enqueue(chunk);
      await new Promise((r) => setTimeout(r, delay));
    },
  });
}

const mdText = ref("");
const isRender = ref(true);

async function clickHandle() {
  mdText.value = "";
  isRender.value = true;
  const res = await fetch("./md.md");
  const md = await res.text();
  const stream = createStream(md);
  for await (const chunk of stream) {
    mdText.value += chunk;
  }
  isRender.value = false;
}

onMounted(clickHandle);
</script>

<template>
  <div>
    <button @click="clickHandle" :disabled="isRender">Re-generate ~</button>
    <article class="vue-markdown-wrapper">
      <VueMarkdownRenderer :md="mdText" />
    </article>
  </div>
</template>

为什么不用现成的库?

  • markdown-it 等常用库 不支持流式渲染
  • 现有方案缺乏良好的 动画与高亮支持
  • 大多数 Markdown 渲染方式依赖 v-html性能和可控性都较差

因此我将 Vue、Shiki 和流式渲染机制组合,封装出这个高效、美观、易用的 Markdown 渲染组件。开发者只需几行代码,就能轻松实现类似 AI 对话的「边输出边渲染 + 高亮 + 动画」效果。

项目结构简介

  • VueMarkdownRenderer.ts:组件主入口,核心的响应式渲染逻辑
  • segmentText.ts:文本拆分与动画粒度处理模块

最后

虽然 vue-mdr 的实现并不复杂,但它显著提升了我的开发效率和终端用户体验。如果你正在做 AI 聊天、内容生成、知识库问答等应用,这个组件或许正好适合你!

相关推荐
Nicander24 分钟前
我给 Excalidraw 做了一个本地工作区:DrawSpace
前端·开源
linux_cfan2 小时前
17 · 引擎适配器全景:HLS/DASH/Vimeo/Mux/Cast
前端·javascript·音视频
吨吨ai2 小时前
Codex 长会话上下文管理:会话拆分与状态交接的工程化实践
chatgpt
计算机魔术师3 小时前
烧掉2780亿美元还不够?OpenAI的资本豪赌让人头皮发麻
前端
IT_陈寒3 小时前
Java线程池用错参数,我的服务居然悄悄崩溃了
前端·人工智能·后端
守城小轩3 小时前
AcBoter 多账号管理指南:隐私与设置选项(五)
chatgpt·codex·acboter
卡布鲁4 小时前
React useMemo 与 useCallback 完全指南:原理、场景与避坑
前端·react.js
碳基修炼4 小时前
排查记:本地 devServer 是 http,浏览器却把 302 重定向升级成了 https
前端·http
步行cgn4 小时前
Spring p 命名空间注入详解
java·前端·spring
何何____4 小时前
Vue 生命周期详解
前端·javascript