mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 16:26:57 +08:00
fix(web): Typewriter 更稳健—charAt防越界、sanitizedLines防空值、pre-wrap防换行丢失
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
|
||||||
interface TypewriterProps {
|
interface TypewriterProps {
|
||||||
lines: string[]
|
lines: string[]
|
||||||
@@ -21,21 +21,23 @@ export default function Typewriter({
|
|||||||
const charIndexRef = useRef(0)
|
const charIndexRef = useRef(0)
|
||||||
const timerRef = useRef<number | null>(null)
|
const timerRef = useRef<number | null>(null)
|
||||||
const blinkRef = useRef<number | null>(null)
|
const blinkRef = useRef<number | null>(null)
|
||||||
|
const sanitizedLines = useMemo(() => lines.map((l) => String(l ?? '')), [lines])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function typeNext() {
|
function typeNext() {
|
||||||
const currentLine = lines[lineIndexRef.current] ?? ''
|
const currentLine = sanitizedLines[lineIndexRef.current] ?? ''
|
||||||
if (charIndexRef.current < currentLine.length) {
|
if (charIndexRef.current < currentLine.length) {
|
||||||
setTypedLines((prev) => {
|
setTypedLines((prev) => {
|
||||||
const next = [...prev]
|
const next = [...prev]
|
||||||
next[next.length - 1] = (next[next.length - 1] || '') + currentLine[charIndexRef.current]
|
const ch = currentLine.charAt(charIndexRef.current)
|
||||||
|
next[next.length - 1] = (next[next.length - 1] || '') + ch
|
||||||
return next
|
return next
|
||||||
})
|
})
|
||||||
charIndexRef.current += 1
|
charIndexRef.current += 1
|
||||||
timerRef.current = window.setTimeout(typeNext, typingSpeed)
|
timerRef.current = window.setTimeout(typeNext, typingSpeed)
|
||||||
} else {
|
} else {
|
||||||
// 行结束
|
// 行结束
|
||||||
if (lineIndexRef.current < lines.length - 1) {
|
if (lineIndexRef.current < sanitizedLines.length - 1) {
|
||||||
lineIndexRef.current += 1
|
lineIndexRef.current += 1
|
||||||
charIndexRef.current = 0
|
charIndexRef.current = 0
|
||||||
setTypedLines((prev) => [...prev, ''])
|
setTypedLines((prev) => [...prev, ''])
|
||||||
@@ -61,7 +63,7 @@ export default function Typewriter({
|
|||||||
}, [lines, typingSpeed, lineDelay])
|
}, [lines, typingSpeed, lineDelay])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<pre className={className} style={style}>
|
<pre className={className} style={{ whiteSpace: 'pre-wrap', ...style }}>
|
||||||
{typedLines.join('\n')}
|
{typedLines.join('\n')}
|
||||||
<span style={{ opacity: showCursor ? 1 : 0 }}> ▍</span>
|
<span style={{ opacity: showCursor ? 1 : 0 }}> ▍</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|||||||
Reference in New Issue
Block a user