前端模拟 流式文本接口 打字机效果 mockStreamText

源码已在文章最后给出

说明书

mockStreamText 这是一个用于在前端 模拟文本流式 展示效果的工具函数,能够将完整文本按指定的片段大小和时间间隔逐步展示,适用于 模拟 AI 对话回复打字机效果 等场景。函数具备完善的参数验证和错误处理机制,确保运行的健壮性。

参数说明

参数名 类型 必选 说明
fullText string 需要进行流式展示的完整文本内容
options object 配置选项对象,包含以下属性

options 配置项

配置项 类型 默认值 说明
chunkSize number 5 每次展示的文本片段大小(正整数)
interval number 50 每次展示的时间间隔(毫秒,正整数)
onChunk function () => {} 每次片段更新时的回调函数,接收当前已展示的文本作为参数
onFinal function () => {} 文本全部展示完成时的回调函数,接收完整文本作为参数
onError function (err) => console.error(...) 发生错误时的回调函数,接收错误对象作为参数

返回值

返回一个取消函数,调用该函数可以终止流式展示过程并释放相关资源。

错误处理

函数会对输入参数进行严格验证,当参数不符合要求时会通过 onError 回调抛出以下错误:

  • fullText 必须是字符串类型:当第一个参数不是字符串时
  • chunkSize 必须是正整数:当 chunkSize 不是正整数时
  • interval 必须是正整数:当 interval 不是正整数时
  • onChunk, onFinal 和 onError 必须是函数:当回调函数不是函数类型时

使用示例

以下仅展示核心的JS食用方法

(利用vue的响应式,displayText内容变化,会自动触发页面渲染,实现打字机效果)

javascript 复制代码
// 引入前端虚拟流式加载工具类
import { mockStreamText } from "@/utils/typeWriter.js"

const backendText = "这是一段需要流式展示的文本内容...";
const displayText = ref("");
const isStreaming = ref(true);

// 启动流式展示
const cancelStream = mockStreamText(backendText, {
    chunkSize: 5,          // 每次展示5个字符
    interval: 50,          // 每50毫秒展示一次
    onChunk: (text) => {   // 片段更新时更新显示
        displayText.value = text;
    },
    onFinal: (fullText) => {  // 展示完成时
        isStreaming.value = false;
        console.log('流式展示结束');
    },
    onError: (err) => {    // 错误处理
        isStreaming.value = false;
        console.error('发生错误:', err.message);
        // 可以在这里添加错误提示UI
    }
});

// 如需中途取消展示
// cancelStream();

特殊情况处理

  • fullText 为空字符串时,会直接触发 onChunk("")onFinal(""),不启动定时器
  • 调用返回的取消函数后,会终止定时器并标记为已取消,避免后续回调执行

工作原理

  1. 进行参数验证,确保输入符合要求
  2. 初始化状态变量(当前位置、定时器、取消标记等)
  3. 定义核心处理函数 process,负责计算片段、触发回调和状态更新
  4. 立即执行一次 process 并设置定时器循环执行
  5. 返回取消函数,用于终止流程并释放资源

该工具函数源码

javascript 复制代码
// 模拟文本流式展示的工具函数(增强健壮性版本)
export function mockStreamText(fullText, options = {}) {
  // 1. 参数验证与默认值处理
  if (typeof fullText !== "string") {
    throw new TypeError("fullText 必须是字符串类型")
  }

  // 默认配置
  const {
    chunkSize = 5,
    interval = 50,
    onChunk = () => {},
    onFinal = () => {},
    onError = (err) => console.error("流式处理错误:", err),
  } = options

  // 验证配置参数的有效性
  if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
    onError(new Error("chunkSize 必须是正整数"))
    return () => {} // 返回空的取消函数
  }

  if (!Number.isInteger(interval) || interval <= 0) {
    onError(new Error("interval 必须是正整数"))
    return () => {}
  }

  if (
    typeof onChunk !== "function" ||
    typeof onFinal !== "function" ||
    typeof onError !== "function"
  ) {
    onError(new Error("onChunk, onFinal 和 onError 必须是函数"))
    return () => {}
  }

  // 2. 状态变量初始化
  let currentPosition = 0
  let timer = null
  let isCanceled = false
  const textLength = fullText.length

  // 3. 核心处理函数(带错误捕获)
  const process = () => {
    if (isCanceled) return

    try {
      // 计算下一次要展示到的位置
      const nextPosition = Math.min(currentPosition + chunkSize, textLength)

      // 获取当前片段并更新位置
      const currentChunk = fullText.substring(0, nextPosition)
      currentPosition = nextPosition

      // 触发片段回调
      onChunk(currentChunk)

      // 检查是否已经完成所有文本的展示
      if (currentPosition >= textLength) {
        clearInterval(timer)
        timer = null
        onFinal(currentChunk) // 触发结束回调
      }
    } catch (err) {
      // 错误处理
      clearInterval(timer)
      timer = null
      onError(err)
    }
  }

  // 4. 启动流式处理(空文本特殊处理)
  if (textLength === 0) {
    // 空文本直接触发结束回调
    onChunk("")
    onFinal("")
    return () => {}
  }

  // 立即执行一次,然后设置定时器
  process()
  timer = setInterval(process, interval)

  // 5. 返回取消函数(确保资源正确释放)
  return () => {
    if (!isCanceled) {
      isCanceled = true
      if (timer) {
        clearInterval(timer)
        timer = null
      }
    }
  }
}
相关推荐
入秋3 小时前
Three.js后期处理实战:噪点 景深 以及色彩调整
前端·javascript·three.js
Asort3 小时前
JavaScript设计模式(七)——桥接模式:解耦抽象与实现的优雅之道
前端·javascript·设计模式
Darenm1113 小时前
JavaScript事件流:冒泡与捕获的深度解析
开发语言·前端·javascript
渣哥3 小时前
不加 @Primary?Spring 自动装配时可能直接报错!
javascript·后端·面试
@大迁世界3 小时前
第03章: Vue 3 组合式函数深度指南
前端·javascript·vue.js·前端框架·ecmascript
我是日安4 小时前
从零到一打造 Vue3 响应式系统 Day 25 - Watch:清理 SideEffect
前端·javascript·vue.js
小高0074 小时前
🤔「`interface` 和 `type` 到底用哪个?」——几乎每个 TS 新手被这个选择灵魂拷问。
前端·javascript·typescript
我的div丢了肿么办4 小时前
vue3使用h函数如何封装组件和$attrs和props的区别
前端·javascript·vue.js
吃饺子不吃馅4 小时前
大家都在找的手绘/素描风格图编辑器它它它来了
前端·javascript·css