• 简体中文
  • 在 Vue 3 中渲染流式 Markdown

    把收到的片段追加到响应式字符串中,传给 text。streaming 控制未完成语法的修复、平滑输出和末尾效果。

    连接文本流

    下面接收已经解析为文本的异步迭代器。SSE 或其他协议的解码留在请求层:

    <script setup lang="ts">
    import { Fluxdown } from '@fluxdown/vue';
    import { ref } from 'vue';
    
    const text = ref('');
    
    const pending = ref(false);
    
    async function read(chunks: AsyncIterable<string>) {
      text.value = '';
    
      pending.value = true;
    
      try {
        for await (const chunk of chunks) {
          text.value += chunk;
        }
      } finally {
        pending.value = false;
      }
    }
    </script>
    
    <template>
      <Fluxdown :text="text" :streaming="pending" />
    </template>

    在应用发起请求后调用 read(chunks)。流结束时关闭 streaming,组件会完成剩余的平滑输出,再移除末尾效果。

    调整输出

    streaming: true 开启末尾修复、平滑输出和 scale 效果。传入对象可以分别调整:

    <script setup lang="ts">
    import type { StreamingConfig } from '@fluxdown/vue';
    
    import { Fluxdown } from '@fluxdown/vue';
    
    type MessageProps = {
      text: string;
      pending: boolean;
    };
    
    const props = defineProps<MessageProps>();
    
    const streaming: StreamingConfig = {
      repairEnding: true,
      smooth: true,
      effect: ['shad', { length: 3, maskWidth: 18 }],
    };
    </script>
    
    <template>
      <Fluxdown :text="props.text" :streaming="props.pending && streaming" />
    </template>
    配置用途
    repairEnding修复尚未闭合的 Markdown,默认开启。
    smooth平滑显示新到达的内容,默认开启。
    effect选择末尾效果,默认 scale;设为 false 关闭。

    只想显示服务端原本的片段节奏,可以关闭 smooth。自定义 ticker 与 scheduler 的方式见 Core 流式内容。

    四种末尾效果

    效果呈现方式
    scale新文字由模糊、缩小逐渐变得清晰。
    shad用渐变遮罩柔和地展开末尾。
    chunk按收到的片段渐入,适合 smooth: false。
    suffix在末尾显示标记,提示内容还在生成。

    例如,保留网络片段并逐段渐入:

    <Fluxdown
      :text="text"
      :streaming="pending && { smooth: false, effect: 'chunk' }"
    />

    effect 也接受 [名称, 配置] 或多个效果的数组,完整字段见自定义配置。可以在动画效果中查看四种效果的演示。

    切换消息

    每条消息使用独立组件,并把消息标识作为 key。切换到另一条内容时,Vue 会创建新的流式状态,避免把上一条消息的播放进度带过来。

    <Fluxdown :key="message.id" :text="message.text" :streaming="message.pending" />