194 lines
5.0 KiB
JavaScript
194 lines
5.0 KiB
JavaScript
/**
|
||
* 打字机效果管理器
|
||
* 负责管理打字机效果的启动、停止、重置等功能
|
||
*/
|
||
class TypewriterManager {
|
||
constructor(options = {}) {
|
||
// 配置选项
|
||
this.options = {
|
||
typingSpeed: 50, // 打字速度(毫秒)
|
||
cursorText: "", // 光标样式
|
||
...options,
|
||
};
|
||
|
||
// 状态变量
|
||
this.currentMessageContent = ""; // 当前消息的完整内容
|
||
this.displayedContent = ""; // 已显示的内容
|
||
this.typewriterTimer = null; // 打字机定时器
|
||
this.isTyping = false; // 是否正在打字
|
||
|
||
// 回调函数
|
||
this.onCharacterTyped = null; // 每个字符打字时的回调
|
||
this.onTypingComplete = null; // 打字完成时的回调
|
||
this.onContentUpdate = null; // 内容更新时的回调
|
||
}
|
||
|
||
/**
|
||
* 设置回调函数
|
||
* @param {Object} callbacks - 回调函数对象
|
||
* @param {Function} callbacks.onCharacterTyped - 每个字符打字时的回调
|
||
* @param {Function} callbacks.onTypingComplete - 打字完成时的回调
|
||
* @param {Function} callbacks.onContentUpdate - 内容更新时的回调
|
||
*/
|
||
setCallbacks(callbacks) {
|
||
this.onCharacterTyped = callbacks.onCharacterTyped || null;
|
||
this.onTypingComplete = callbacks.onTypingComplete || null;
|
||
this.onContentUpdate = callbacks.onContentUpdate || null;
|
||
}
|
||
|
||
/**
|
||
* 添加内容到当前消息
|
||
* @param {string} content - 要添加的内容
|
||
*/
|
||
addContent(content) {
|
||
if (typeof content !== "string") {
|
||
content = String(content);
|
||
}
|
||
this.currentMessageContent += content;
|
||
|
||
// 如果没有在打字,启动打字机效果
|
||
if (!this.isTyping) {
|
||
this.startTypewriter();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 启动打字机效果
|
||
*/
|
||
startTypewriter() {
|
||
if (this.isTyping) return;
|
||
|
||
this.isTyping = true;
|
||
// 不要在启动时重置displayedContent,而是从当前位置继续
|
||
|
||
this._typeNextChar();
|
||
}
|
||
|
||
/**
|
||
* 打字下一个字符(私有方法)
|
||
*/
|
||
_typeNextChar() {
|
||
// 如果已显示内容长度小于完整内容长度,继续打字
|
||
if (this.displayedContent.length < this.currentMessageContent.length) {
|
||
const nextLength = Math.min(
|
||
this.displayedContent.length + 1,
|
||
this.currentMessageContent.length
|
||
);
|
||
this.displayedContent = this.currentMessageContent.substring(
|
||
0,
|
||
nextLength
|
||
);
|
||
|
||
const displayContent = this.displayedContent;
|
||
|
||
// 调用内容更新回调
|
||
if (this.onContentUpdate) {
|
||
this.onContentUpdate(displayContent);
|
||
}
|
||
|
||
// 调用字符打字回调
|
||
if (this.onCharacterTyped) {
|
||
this.onCharacterTyped(this.displayedContent);
|
||
}
|
||
|
||
// 确保最小延迟,避免定时器堆积
|
||
const delay = Math.max(this.options.typingSpeed, 30); // 设置最小延迟30ms
|
||
this.typewriterTimer = setTimeout(() => {
|
||
this._typeNextChar();
|
||
}, delay);
|
||
} else {
|
||
// 打字完成,移除光标
|
||
if (this.onContentUpdate) {
|
||
this.onContentUpdate(this.currentMessageContent);
|
||
}
|
||
|
||
// 调用打字完成回调
|
||
if (this.onTypingComplete) {
|
||
this.onTypingComplete(this.currentMessageContent);
|
||
}
|
||
|
||
this.stopTypewriter();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 停止打字机效果
|
||
*/
|
||
stopTypewriter() {
|
||
if (this.typewriterTimer) {
|
||
clearTimeout(this.typewriterTimer);
|
||
this.typewriterTimer = null;
|
||
}
|
||
this.isTyping = false;
|
||
}
|
||
|
||
/**
|
||
* 停止打字机效果并保留当前显示的内容
|
||
* 与stopTypewriter不同,这个方法会将当前显示的内容设为最终内容
|
||
*/
|
||
stopAndKeepCurrent() {
|
||
this.stopTypewriter();
|
||
// 将当前显示的内容设为完整内容,避免后续添加更多内容
|
||
this.currentMessageContent = this.displayedContent;
|
||
|
||
// 调用完成回调
|
||
if (this.onTypingComplete) {
|
||
this.onTypingComplete(this.displayedContent);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 重置打字机状态
|
||
*/
|
||
reset() {
|
||
this.currentMessageContent = "";
|
||
this.displayedContent = "";
|
||
this.stopTypewriter();
|
||
}
|
||
|
||
/**
|
||
* 获取当前状态
|
||
* @returns {Object} 当前状态对象
|
||
*/
|
||
getStatus() {
|
||
return {
|
||
isTyping: this.isTyping,
|
||
currentContent: this.currentMessageContent,
|
||
displayedContent: this.displayedContent,
|
||
progress:
|
||
this.currentMessageContent.length > 0
|
||
? this.displayedContent.length / this.currentMessageContent.length
|
||
: 0,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 立即完成打字(跳过动画)
|
||
*/
|
||
completeImmediately() {
|
||
this.stopTypewriter();
|
||
this.displayedContent = this.currentMessageContent;
|
||
|
||
if (this.onContentUpdate) {
|
||
this.onContentUpdate(this.currentMessageContent);
|
||
}
|
||
|
||
if (this.onTypingComplete) {
|
||
this.onTypingComplete(this.currentMessageContent);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 销毁打字机管理器
|
||
*/
|
||
destroy() {
|
||
this.stopTypewriter();
|
||
this.reset();
|
||
this.onCharacterTyped = null;
|
||
this.onTypingComplete = null;
|
||
this.onContentUpdate = null;
|
||
}
|
||
}
|
||
|
||
export default TypewriterManager;
|