在现代 Web 开发中,实现动态文本渲染的需求日益增多。无论是聊天应用、实时通知,还是交互式界面,打字机风格的文本渲染都能显著提升用户体验。最近新写了一个开源的 NPM 包——Typewriter-SSE,它通过 Server-Sent Events (SSE) 技术实现了流式文本传输和打字机效果渲染。项目代码已开源,可在 GitHub 查看。效果见:

一、SSE 技术简介

Server-Sent Events (SSE) 是一种允许服务器向浏览器单向推送数据的技术。与传统的轮询或 WebSocket 不同,SSE 基于 HTTP 协议,仅支持文本数据传输,且服务器到客户端的连接保持开启状态,直到服务器关闭连接。SSE 的主要特点包括:
  1. 单向通信:仅支持服务器向客户端推送数据,适合不需要双向通信的场景。
  2. 轻量级:基于 HTTP 协议,无需额外的 WebSocket 协议支持。
  3. 自动重连:浏览器会自动处理连接中断后的重连逻辑。
  4. 简单易用:通过 EventSource 接口即可在客户端实现 SSE 的接收。
SSE 的典型应用场景包括实时通知、动态数据更新等,尤其适合需要服务器主动推送数据的场景。
 

Typewriter-SSE 的实现原理

Typewriter-SSE 结合了 SSE 技术和前端动画,实现了流式文本的打字机效果渲染。其核心逻辑包括:
  1. SSE 数据接收:通过 EventSource 接口连接到服务器端的 SSE 端点,接收服务器推送的文本数据。
  2. 逐字渲染:将接收到的文本数据逐字渲染到指定的容器中,通过定时器控制每个字符的渲染速度,模拟打字机效果。
  3. 光标动画:通过 CSS 动画实现光标的闪烁效果,增强视觉体验。
  4. 交互控制:提供暂停、恢复、跳过和清空等控制方法,允许用户在渲染过程中进行操作

二、如何安装和使用 Typewriter-SSE?

安装 Typewriter-SSE 非常简单,只需要通过 npm 命令即可完成:
npm install typewriter-sse 

在项目中使用

import TypewriterSSE from 'typewriter-sse';

const writer = new TypewriterSSE({
container: '#output', // 指定文本渲染的容器
endpoint: '/sse?q=hello world', // SSE 服务端的 URL
cursor: {
blink: true, // 是否让光标闪烁
color: '#0f0', // 光标颜色
char: '|' // 光标字符
},
onComplete: () => console.log('Finished typing!') // 文本渲染完成后的回调函数
}); writer.start();

  

三、主要功能和配置选项

1. 打字机效果

Typewriter-SSE 的核心功能是将文本逐字渲染到指定的容器中,模拟打字机的效果。你可以通过 typingSpeed 选项来控制每个字符的延迟时间,从而调整打字的速度。

2. SSE 支持

通过 SSE 技术,Typewriter-SSE 能够动态接收来自服务器的文本数据。这意味着你可以将文本分段发送到客户端,而客户端会逐字渲染这些文本。这种技术特别适合实现聊天机器人、实时通知等场景。

3. 光标自定义

你可以通过 cursor 选项来自定义光标的样式,包括是否闪烁、颜色和字符。这让你可以根据项目的整体风格来调整光标的视觉效果。

4. 事件回调

Typewriter-SSE 提供了多种事件回调函数,例如 onChar(每个字符渲染时触发)和 onComplete(文本渲染完成时触发)。这些回调函数可以帮助你更好地控制文本渲染过程,并在合适的时候执行其他逻辑。

5. 暂停、恢复、跳过和清空

Typewriter-SSE 提供了暂停、恢复、跳过和清空文本的控制方法。你可以通过这些方法来实现更复杂的交互逻辑,例如让用户暂停文本渲染、跳过未渲染的文本或清空已渲染的文本。
 
 

四、一个完整的示例

为了让大家更好地理解 Typewriter-SSE 的使用方法,我将展示一个完整的示例。这个示例包括一个简单的服务器端代码和一个客户端页面,用于演示 Typewriter-SSE 的效果。

1. 服务器端代码

这是一个基于 Node.js 的简单服务器代码,它通过 SSE 技术向客户端发送分段的文本数据。
const express = require('express');
const path = require('path');
const app = express();
const PORT = 3000; app.use(express.static(path.join(__dirname, 'public'))); app.get('/sse', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive'); const query = req.query.q || "你没有输入任何内容哦~"; const paragraphs = [
`你输入的是「${query}」`,
`这是段模拟的第一个回复 `,
`接下来是第二段回复 `,
`最后一段啦,演示完毕 `
]; let pIndex = 0;
let charIndex = 0; const interval = setInterval(() => {
if (pIndex < paragraphs.length) {
if (charIndex < paragraphs[pIndex].length) {
res.write(`data: ${paragraphs[pIndex][charIndex++]}\n\n`);
} else {
res.write(`data: \n\n`); // 空行分段
pIndex++;
charIndex = 0;
}
} else {
clearInterval(interval);
res.write('event: done\n');
res.write('data: end\n\n');
res.end();
}
}, 50);
}); app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});

  

2. 客户端页面

这是一个简单的 HTML 页面,它使用 Typewriter-SSE 来渲染来自服务器的文本数据。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>打字机 + SSE + 控制面板</title>
<style>
body {
background: #111;
color: #0f0;
font-family: monospace;
padding: 20px;
}
#output {
white-space: pre-wrap;
font-size: 1.2em;
min-height: 100px;
margin-top: 1em;
}
input[type="text"], button {
padding: 8px;
font-size: 1em;
margin: 5px 5px 5px 0;
background: #222;
color: #0f0;
border: 1px solid #0f0;
}
.controls {
margin-top: 10px;
}
</style>
</head>
<body> <h2>打字机效果演示</h2>
<input type="text" id="prompt" placeholder="请输入..." />
<div class="controls">
<button id="send">发送</button>
<button id="pause">暂停</button>
<button id="resume">继续</button>
<button id="skip">跳过</button>
<button id="delete">清空输出</button>
</div>
<div id="output"></div> <script type="module">
import TypewriterSSE from './typewriter-sse.js'; let writer = null; document.getElementById('send').addEventListener('click', () => {
const query = document.getElementById('prompt').value.trim();
if (!query) return alert('请输入内容');
if (writer) writer.stop(); const output = document.getElementById('output');
output.textContent = ""; writer = new TypewriterSSE({
container: output,
endpoint: '/sse?q=' + encodeURIComponent(query),
cursor: { blink: true, color: '#0f0', char: '|' },
onComplete: () => console.log('输入完成')
});
writer.start();
}); document.getElementById('pause').addEventListener('click', () => {
if (writer) writer.pause();
}); document.getElementById('resume').addEventListener('click', () => {
if (writer) writer.resume();
}); document.getElementById('skip').addEventListener('click', () => {
if (writer) writer.skip();
}); document.getElementById('delete').addEventListener('click', () => {
if (writer) writer.deleteAll();
});
</script> </body>
</html>

  

总结

Typewriter-SSE 是一个基于 SSE 技术实现的流式文本渲染库,能够为 Web 应用带来动态的打字机效果。它不仅支持流式文本传输,还提供了丰富的交互控制功能。如果你对 Typewriter-SSE 感兴趣,或者希望了解更多实现细节,欢迎访问 GitHub 仓库

【大前端攻城狮之路】用 Typewriter-SSE 实现打字机效果的更多相关文章

  1. 【大前端攻城狮之路】JavaScript函数式编程

    转眼之间已入五月,自己毕业也马上有三年了.大学计算机系的同学大多都在北京混迹,大家为了升职加薪,娶媳妇买房,熬夜加班跟上线,出差pk脑残客户.同学聚会时有不少兄弟已经体重飙升,开始关注13号地铁线上铺 ...

  2. 【大前端攻城狮之路·二】Javascript&QA⼯程师

    今天给大家分享的主题的是Javascript&QA⼯程师.看到这个主题,可能有人问:前端开发完就OK了,剩下的丢给测试就行,哪里还需要关心这些?但事实上呢,测试是前端开发非常重要的环节,也是迈 ...

  3. java攻城狮之路(Android篇)--BroadcastReceiver&Service

    四大组件:activity 显示. contentProvider 对外暴露自己的数据给其他的应用程序.BroadcastReceiver 广播接收者,必须指定要接收的广播类型.必须明确的指定acti ...

  4. java攻城狮之路(Android篇)--Activity生命

    一:Activity的激活 1.写一个类 extends Activity Activity是android的四大组件之一.Activity的激活分为显式意图激活和隐式意图激活.如果一个activit ...

  5. web前端攻城狮整理的收藏夹

    作为一名web前端开发工程师你的收藏夹存对了吗?下面是一份互联网上流传甚广的web前端开发收藏夹资源,包含学习网站.JS库.常用工具.常用插件.资讯书籍等资源.速速转存吧~   一.学习网站   W3 ...

  6. 自己平时收集的css、html笔记(适合初级前端攻城狮)

    实习了一年时间,陆陆续续记录下来一堆笔记,不过也丢失了一些... 以后会持续更新.扩展,现在把碰到的知识点归纳于此,方便翻阅 一.html部分 1.取消iPhone自动识别数字为拨打号码 <me ...

  7. java攻城狮之路--复习xml&dom_pull编程

    xml&dom_pull编程: 1.去掉欢迎弹窗界面:在window项的preferences选项中输入“configuration center” 找到这一项然后     把复选框勾去即可. ...

  8. 大数据攻城狮之Hadoop伪分布式篇

    对于初学大数据的萌新来说,初次接触Hadoop伪分布式搭建的同学可能是一脸萌笔的,那么这一次小编就手把手的教大家在centos7下搭建Hadoop伪分布式. 底层环境: VMware Workstat ...

  9. java攻城狮之路(Android篇)--widget_webview_metadata_popupwindow_tabhost_分页加载数据_菜单

    一.widget:桌面小控件1 写一个类extends AppWidgetProvider 2 在清单文件件中注册: <receiver android:name=".ExampleA ...

  10. java攻城狮之路(Android篇)--MP3 MP4、拍照、国际化、样式主题、图片移动和缩放

    一.MP3播放器 查看Android API文档可以看到MediaPlayer状态转换图: 练习: package com.shellway.mp3player; import java.io.Fil ...

随机推荐

  1. Python 合并 Excel 单元格

    合并 Excel 单元格是 Excel 数据处理和表格设计中的一项常用操作.例如,在制作表格标题时,经常会将多个单元格合并,使标题能够跨列显示,更加醒目和美观.此外,当对数据进行分类时,为了使同一类别 ...

  2. 使用nvm管理node.js版本,方便vue2,vue3开发

    在Vue项目开发过程中,我们常常会遇到同时维护Vue2和Vue3项目的情况.由于不同版本的Vue对Node.js 版本的要求有所差异,这就使得Node.js 版本管理成为了一个关键问题.NVM(Nod ...

  3. [SDOI2009] 晨跑 题解

    每个点拆成入点和出点. 发现每个点.每条边都只能经过一次,所以所有边的容量都是 \(1\). #include<bits/stdc++.h> #define ll long long us ...

  4. 发那科机器人R2000iC控制柜常见故障类型

    发那科机器人维修R2000iC控制柜常见故障类型 电源故障: 发那科机器人R2000iC控制柜不能正常供电,可能是由于电源线路损坏.保险丝烧断.电源模块故障或电压不稳定等原因造成. 通信故障: 控制柜 ...

  5. 一段VUE代码:通过组件封装全局方法、自定义指令和注册组件

    index.js // 插件定义第一种方式,对象:拥有 install() 方法的对象 const myPlugin = { install(app, options) { // 配置全局方法 app ...

  6. SQL Server 2025 AI相关能力初探

    SQL Server 在2024年11月开始进行社区私有预览(链接),由于涉及AI能力,我也是第一时间申请了内侧资格,悲剧的是,直到2025年2月,才拿到预览版的测试资格-.-,此时已经是CTP1.3 ...

  7. 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异

    从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异 引言 在开发 Web 应用时,处理 HTTP 错误响应是常见的任务,尤其是在客户端代码中捕获并向用户展示错误信息.然而,当使用 HTTP ...

  8. 一款基于.NET开源、强大的网络管理和网络问题排查工具!

    前言 今天大姚给大家分享一款基于.NET开源.免费.功能强大的网络管理和网络问题排查工具:NETworkManager. 项目介绍 NETworkManager 是一个基于.NET开源(GPL-3.0 ...

  9. idea 缺失右侧maven窗口

    最近整了一个别人的项目到本地,发现在git下载项目到本地后,再通过idea的打开项目后,缺失了右侧的maven窗口. 注: idea是有安装到maven(idea默认是已经安装好的) 打开的项目也是m ...

  10. mac 如何开启指定端口供外部访问?

    前言 需要 mac 上开放指定端口,指定 ip 访问 解决 在 macOS 上开放一个端口,并指定只能特定的 IP 访问,可以使用 macOS 内置的 pfctl(Packet Filter)工具来实 ...