Skip to content

Commit 70c5534

Browse files
committed
feat: add streaming rendering feature with adjustable speed and interval settings
1 parent fc49bd3 commit 70c5534

File tree

1 file changed

+154
-2
lines changed

1 file changed

+154
-2
lines changed

playground/src/pages/test.vue

Lines changed: 154 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ graph TD
3232
\`\`\`
3333
`)
3434
35+
// 流式渲染相关状态
36+
const streamContent = ref<string>('')
37+
const isStreaming = ref(false)
38+
const streamSpeed = ref(1) // 每次添加的字符数,可调整速度
39+
const streamInterval = ref(16) // 每次更新的时间间隔(毫秒)
40+
const showStreamSettings = ref(false) // 是否显示流式渲染设置
41+
3542
// 预加载 Monaco 编辑器和 worker
3643
getUseMonaco()
3744
setKaTeXWorker(new KatexWorker())
@@ -195,6 +202,56 @@ onMounted(() => {
195202
restoreFromUrl()
196203
shareUrl.value = window.location.href
197204
})
205+
206+
// 流式渲染函数
207+
let streamTimer: number | null = null
208+
209+
function startStreamRender() {
210+
if (isStreaming.value) {
211+
// 如果正在流式渲染,停止它
212+
stopStreamRender()
213+
return
214+
}
215+
216+
// 重置流式内容
217+
streamContent.value = ''
218+
isStreaming.value = true
219+
let currentIndex = 0
220+
const fullText = input.value
221+
222+
const streamStep = () => {
223+
if (currentIndex >= fullText.length) {
224+
// 完成流式渲染
225+
stopStreamRender()
226+
return
227+
}
228+
229+
// 每次截取指定数量的字符
230+
const nextIndex = Math.min(currentIndex + streamSpeed.value, fullText.length)
231+
streamContent.value = fullText.slice(0, nextIndex)
232+
currentIndex = nextIndex
233+
234+
// 继续下一次渲染,使用用户设置的时间间隔
235+
streamTimer = window.setTimeout(streamStep, streamInterval.value)
236+
}
237+
238+
streamStep()
239+
}
240+
241+
function stopStreamRender() {
242+
if (streamTimer !== null) {
243+
clearTimeout(streamTimer)
244+
streamTimer = null
245+
}
246+
isStreaming.value = false
247+
// 确保显示完整内容
248+
if (streamContent.value && streamContent.value !== input.value)
249+
streamContent.value = input.value
250+
}
251+
252+
function toggleStreamSettings() {
253+
showStreamSettings.value = !showStreamSettings.value
254+
}
198255
</script>
199256

200257
<template>
@@ -206,6 +263,20 @@ onMounted(() => {
206263
</h2>
207264
<div class="text-sm text-gray-500 flex items-center gap-3">
208265
<span>左侧输入,右侧预览</span>
266+
<button
267+
class="px-2 py-1 rounded text-sm flex items-center gap-2"
268+
:class="isStreaming ? 'bg-red-600 text-white' : 'bg-purple-600 text-white'"
269+
@click="startStreamRender"
270+
>
271+
{{ isStreaming ? '停止流式渲染' : '流式渲染' }}
272+
</button>
273+
<button
274+
class="px-2 py-1 bg-gray-500 text-white rounded text-sm"
275+
:class="{ 'bg-gray-700': showStreamSettings }"
276+
@click="toggleStreamSettings"
277+
>
278+
⚙️ 设置
279+
</button>
209280
<button :disabled="isWorking" class="px-2 py-1 bg-blue-600 text-white rounded text-sm flex items-center gap-2" @click="generateAndCopy">
210281
生成并复制分享链接
211282
</button>
@@ -215,16 +286,66 @@ onMounted(() => {
215286
</div>
216287
</div>
217288

289+
<!-- 流式渲染设置面板 -->
290+
<div v-if="showStreamSettings" class="mb-4 p-4 bg-white dark:bg-gray-800 rounded border border-purple-300 dark:border-purple-700 shadow-md">
291+
<h3 class="text-sm font-semibold mb-3 text-gray-800 dark:text-gray-200">
292+
流式渲染设置
293+
</h3>
294+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
295+
<div>
296+
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">
297+
每次截取字符数: <span class="text-purple-600 dark:text-purple-400 font-semibold">{{ streamSpeed }}</span>
298+
</label>
299+
<input
300+
v-model.number="streamSpeed"
301+
type="range"
302+
min="1"
303+
max="100"
304+
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
305+
>
306+
<div class="flex justify-between text-xs text-gray-500 mt-1">
307+
<span>1 (慢)</span>
308+
<span>100 (快)</span>
309+
</div>
310+
</div>
311+
<div>
312+
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">
313+
更新间隔(毫秒): <span class="text-purple-600 dark:text-purple-400 font-semibold">{{ streamInterval }}ms</span>
314+
</label>
315+
<input
316+
v-model.number="streamInterval"
317+
type="range"
318+
min="10"
319+
max="500"
320+
step="10"
321+
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
322+
>
323+
<div class="flex justify-between text-xs text-gray-500 mt-1">
324+
<span>10ms (快)</span>
325+
<span>500ms (慢)</span>
326+
</div>
327+
</div>
328+
</div>
329+
<div class="mt-3 p-2 bg-purple-50 dark:bg-purple-900/20 rounded text-xs text-gray-600 dark:text-gray-400">
330+
💡 提示:字符数越大或间隔越小,渲染速度越快
331+
</div>
332+
</div>
333+
218334
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
219335
<div>
220336
<label class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-200">输入</label>
221337
<textarea v-model="input" rows="18" class="w-full p-3 rounded border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm text-gray-900 dark:text-gray-100 resize-none" />
222338
</div>
223339

224340
<div>
225-
<label class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-200">预览</label>
341+
<label class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-200">
342+
预览
343+
<span v-if="streamContent" class="ml-2 text-xs text-purple-600 dark:text-purple-400">
344+
(流式渲染模式 {{ isStreaming ? '- 渲染中...' : '- 已完成' }})
345+
</span>
346+
</label>
226347
<div class="max-w-none p-3 rounded border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 min-h-[14rem] overflow-auto">
227-
<MarkdownRender :content="input" />
348+
<MarkdownRender :content="streamContent || input" />
228349
</div>
229350
<div class="mt-2 text-xs text-gray-500 break-words">
230351
<template v-if="tooLong">
@@ -368,4 +489,35 @@ onMounted(() => {
368489
position: relative;
369490
animation: renderingGlow 2s ease-in-out infinite;
370491
}
492+
493+
/* 滑块样式优化 */
494+
input[type="range"]::-webkit-slider-thumb {
495+
appearance: none;
496+
width: 16px;
497+
height: 16px;
498+
border-radius: 50%;
499+
background: #9333ea;
500+
cursor: pointer;
501+
transition: all 0.2s;
502+
}
503+
504+
input[type="range"]::-webkit-slider-thumb:hover {
505+
background: #7c3aed;
506+
transform: scale(1.2);
507+
}
508+
509+
input[type="range"]::-moz-range-thumb {
510+
width: 16px;
511+
height: 16px;
512+
border-radius: 50%;
513+
background: #9333ea;
514+
cursor: pointer;
515+
border: none;
516+
transition: all 0.2s;
517+
}
518+
519+
input[type="range"]::-moz-range-thumb:hover {
520+
background: #7c3aed;
521+
transform: scale(1.2);
522+
}
371523
</style>

0 commit comments

Comments
 (0)