Commit f7301462 authored by wuhao's avatar wuhao 🎯

asder

parent 008b6ddf
// app/api/streaming/route.js // app/api/streaming/route.js
const story = [
"李焊玲是一个女汉子。",
"她力大无穷,",
"喜欢挑战各种极限运动。",
"有一天,",
"她决定去攀登一座险峻的高山。",
"在山脚下,",
"她遇到了一群正准备放弃的登山者。",
"李焊玲鼓励他们,",
"说,",
"只要坚持,",
"没有什么是不可能的。",
"于是,",
"她带领这群登山者一起向山顶进发。",
"一路上,",
"她用自己的力量帮助大家克服各种困难,",
"大家都被她的勇气和毅力所感染。",
"最终,",
"在李焊玲的带领下,",
"他们成功登上了山顶。",
"大家欢呼雀跃,",
"李焊玲却笑着说,",
"这只是人生中的一个小挑战,",
"未来还有更多的冒险等着我们。",
"从那以后,",
"李焊玲的故事在登山者中广为流传,",
"她成为了大家心目中的英雄。"
];
export async function GET(request) { export async function GET(request) {
const readable = new ReadableStream({ const readable = new ReadableStream({
async start(controller) { async start(controller) {
// 第一块数据 // 第一块数据
controller.enqueue("Hello,\n"); // controller.enqueue("\n");
// 模拟延迟并逐步发送数据块 // 模拟延迟并逐步发送数据块
const encoder = new TextEncoder(); const encoder = new TextEncoder();
for (let i = 0; i < 5; i++) { for (let i = 0; i < story.length; i++) {
await new Promise((resolve) => setTimeout(resolve, 1000)); await new Promise((resolve) => setTimeout(resolve, story[i].length*50));
controller.enqueue( controller.enqueue(
encoder.encode( encoder.encode(
i == 4 ? "End" : `This is a streaming response part ${i + 1}.\n` `${story[i]} \n`
) )
); );
} }
......
...@@ -31,3 +31,69 @@ body { ...@@ -31,3 +31,69 @@ body {
text-wrap: balance; text-wrap: balance;
} }
} }
.loader {
width: 48px;
height: 48px;
margin:24px auto 24px auto;
position: relative;
}
.loader:before {
content: '';
width: 48px;
height: 5px;
background: #f0808050;
position: absolute;
top: 60px;
left: 0;
border-radius: 50%;
animation: shadow324 0.5s linear infinite;
}
.loader:after {
content: '';
width: 100%;
height: 100%;
background: #f08080;
position: absolute;
top: 0;
left: 0;
border-radius: 4px;
animation: jump7456 0.5s linear infinite;
}
@keyframes jump7456 {
15% {
border-bottom-right-radius: 3px;
}
25% {
transform: translateY(9px) rotate(22.5deg);
}
50% {
transform: translateY(18px) scale(1, .9) rotate(45deg);
border-bottom-right-radius: 40px;
}
75% {
transform: translateY(9px) rotate(67.5deg);
}
100% {
transform: translateY(0) rotate(90deg);
}
}
@keyframes shadow324 {
0%,
100% {
transform: scale(1, 1);
}
50% {
transform: scale(1.2, 1);
}
}
\ No newline at end of file
...@@ -7,6 +7,7 @@ let currentIndex = 0; ...@@ -7,6 +7,7 @@ let currentIndex = 0;
export default function Home() { export default function Home() {
const [data, setData] = useState(""); const [data, setData] = useState("");
const [displayedData, setDisplayedData] = useState(""); const [displayedData, setDisplayedData] = useState("");
const [loading, setLoading] = useState(false);
const fetchData = async () => { const fetchData = async () => {
const response = await fetch("/api"); const response = await fetch("/api");
...@@ -15,8 +16,12 @@ export default function Home() { ...@@ -15,8 +16,12 @@ export default function Home() {
let result = ""; let result = "";
while (true) { while (true) {
setLoading(true);
const { value, done } = await reader.read(); const { value, done } = await reader.read();
if (done) break; if (done) {
setLoading(false);
break;
}
result += decoder.decode(value); //拼接结果 result += decoder.decode(value); //拼接结果
setData((prevData) => `${prevData} ${decoder.decode(value)}`); setData((prevData) => `${prevData} ${decoder.decode(value)}`);
} }
...@@ -24,7 +29,6 @@ export default function Home() { ...@@ -24,7 +29,6 @@ export default function Home() {
useEffect(() => { useEffect(() => {
if (!data || !data[currentIndex]) return; if (!data || !data[currentIndex]) return;
const intervalId = setInterval(() => { const intervalId = setInterval(() => {
if (currentIndex < data.length) { if (currentIndex < data.length) {
setDisplayedData((prev) => prev + (data[currentIndex] || "")); setDisplayedData((prev) => prev + (data[currentIndex] || ""));
...@@ -32,17 +36,22 @@ export default function Home() { ...@@ -32,17 +36,22 @@ export default function Home() {
} else { } else {
clearInterval(intervalId); clearInterval(intervalId);
} }
}, 50); // 控制打字速度,值越小速度越快 }, 15); // 控制打字速度,值越小速度越快
return () => clearInterval(intervalId); return () => clearInterval(intervalId);
}, [data]); }, [data]);
return ( return (
<main className="flex min-h-screen flex-col items-center justify-between p-24"> <main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex"> <div className="z-10 w-full items-center justify-between font-mono text-sm lg:flex">
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"> <p
Get started by editing&nbsp; onClick={() => {
<code className="font-mono font-bold">src/app/page.js</code> setData("");
setDisplayedData("");
currentIndex = 0;
}}
className="cursor-pointer fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"
>
清空
</p> </p>
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none"> <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
<a <a
...@@ -76,6 +85,26 @@ export default function Home() { ...@@ -76,6 +85,26 @@ export default function Home() {
</div> </div>
<div className="mb-32 flex text-center lg:text-left w-full gap-4"> <div className="mb-32 flex text-center lg:text-left w-full gap-4">
<a
className="group rounded-lg border border-transparent px-5 py-4 bg-white flex-1"
rel="noopener noreferrer"
>
<h2 className={`mb-3 text-2xl font-semibold`}>
一次性返回{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
{loading ? (
<div className="loader"></div>
) : (
<p
className={`m-0 bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-purple-500 text-base`}
>
{data || "等待数据接入..."}
</p>
)}
</a>
<a <a
className="group rounded-lg border border-transparent px-5 py-4 bg-white flex-1" className="group rounded-lg border border-transparent px-5 py-4 bg-white flex-1"
rel="noopener noreferrer" rel="noopener noreferrer"
...@@ -86,7 +115,11 @@ export default function Home() { ...@@ -86,7 +115,11 @@ export default function Home() {
-&gt; -&gt;
</span> </span>
</h2> </h2>
<p className={`m-0 text-sm bg-clip-text text-transparent bg-gradient-to-r from-orange-500 to-green-500 text-base`}>{data || "pending..."}</p> <p
className={`m-0 bg-clip-text text-transparent bg-gradient-to-r from-orange-500 to-green-500 text-base`}
>
{data || "等待数据接入..."}
</p>
</a> </a>
<a <a
...@@ -99,10 +132,10 @@ export default function Home() { ...@@ -99,10 +132,10 @@ export default function Home() {
-&gt; -&gt;
</span> </span>
</h2> </h2>
<p className={`m-0 text-sm `}> <p
<span className="bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-violet-500 text-base"> className={`m-0 bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-violet-500 text-base`}
{displayedData || "pending..."} >
</span> {displayedData || "等待数据接入..."}
</p> </p>
</a> </a>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment