Skip to content

Instantly share code, notes, and snippets.

@cxOrz
Created October 9, 2023 07:50
Show Gist options
  • Save cxOrz/9b166767605fa7321c460c0009e48d83 to your computer and use it in GitHub Desktop.
Save cxOrz/9b166767605fa7321c460c0009e48d83 to your computer and use it in GitHub Desktop.
Text Typing Animation React Component
import TypingSpan from '@/components/TypingSpan/TypingSpan';
export default function Test() {
return (
<main>
<TypingSpan items={['TypingSpan'],['Hello World']} />
</main>
);
}
.typing_span {
display: inline-block;
}
.typing_span>span::after {
display: inline-block;
content: '';
width: 0.5em;
height: 1em;
background-color: currentColor;
}
.cursor_blink::after {
animation: blink 1s infinite;
}
@keyframes blink {
0% {
visibility: visible;
}
50% {
visibility: hidden;
}
100% {
visibility: hidden;
}
}
'use client';
import React, { useEffect, useRef } from 'react';
import './TypingSpan.css';
interface Props {
items: string[];
}
const delay = (ms = 200) => {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
};
const TypingSpan: React.FC<Props> = ({ items }) => {
const spanRef = useRef<HTMLSpanElement>(null);
const typingStrs = items.map(item => ' ' + item);
useEffect(() => {
const animateTyping = async () => {
if (spanRef.current) {
// 每一条字符串逐个展示
for (let i = 0; i < typingStrs.length;) {
// 打字效果
for (let j = 0; j < typingStrs[i].length; j++) {
spanRef.current.innerText = typingStrs[i].slice(0, j + 1);
await delay(200);
}
// 光标闪烁
spanRef.current.classList.add('cursor_blink');
await delay(2000);
spanRef.current.classList.remove('cursor_blink');
// 删除效果
for (let j = typingStrs[i].length; j > 0; j--) {
spanRef.current.innerText = typingStrs[i].slice(0, j);
await delay(200);
}
i++;
if (i === typingStrs.length) i = 0;
}
}
};
animateTyping();
}, [spanRef]);
return (
<div className='typing_span'>
<span ref={spanRef}></span>
</div>
);
};
export default TypingSpan;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment