打造一个支持流式输出的 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 聊天、内容生成、知识库问答等应用,这个组件或许正好适合你!

相关推荐
小满zs3 小时前
Zustand 第五章(订阅)
前端·react.js
涵信4 小时前
第一节 基础核心概念-TypeScript与JavaScript的核心区别
前端·javascript·typescript
谢尔登4 小时前
【React】常用的状态管理库比对
前端·spring·react.js
编程乐学(Arfan开发工程师)4 小时前
56、原生组件注入-原生注解与Spring方式注入
java·前端·后端·spring·tensorflow·bug·lua
小公主4 小时前
JavaScript 柯里化完全指南:闭包 + 手写 curry,一步步拆解原理
前端·javascript
姑苏洛言6 小时前
如何解决答题小程序大小超过2M的问题
前端
GISer_Jing7 小时前
JWT授权token前端存储策略
前端·javascript·面试
开开心心就好7 小时前
电脑扩展屏幕工具
java·开发语言·前端·电脑·php·excel·batch
拉不动的猪7 小时前
es6常见数组、对象中的整合与拆解
前端·javascript·面试
GISer_Jing7 小时前
Vue Router知识框架以及面试高频问题详解
前端·vue.js·面试