Skip to content

Commit a1ec0b2

Browse files
committed
docs: 添加 useDelayedLoading 对应 demo
1 parent 77fc6b9 commit a1ec0b2

File tree

4 files changed

+325
-4
lines changed

4 files changed

+325
-4
lines changed

example/src/App.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ function loadScript_() {
2727
<RouterLink to="/use-sms-countdown">
2828
UseSmsCountdown
2929
</RouterLink>
30+
<RouterLink to="/use-delayed-loading">
31+
UseDelayedLoading
32+
</RouterLink>
3033
</nav>
3134
</div>
3235
</header>

example/src/router/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ const router = createRouter({
2121
path: '/use-sms-countdown',
2222
name: 'use-sms-countdown',
2323
component: () => import('../views/UseSmsCountdownView.vue'),
24-
}
24+
},
25+
{
26+
path: '/use-delayed-loading',
27+
name: 'use-delayed-loading',
28+
component: () => import('../views/UseDelayedLoadingView.vue'),
29+
},
2530
],
2631
})
2732

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
<template>
2+
<div class="delayed-loading-demo">
3+
<h1>useDelayedLoading 演示</h1>
4+
5+
<div class="demo-section">
6+
<h2>基本使用</h2>
7+
<div class="demo-card">
8+
<div class="demo-controls">
9+
<button @click="startLoading" :disabled="loading">开始加载 ({{ requestTime }}ms)</button>
10+
<div class="loading-config">
11+
<label>
12+
是否使用 useDelayedLoading 优化 loading 的显示:
13+
<input type="checkbox" v-model="isOptimized" />
14+
</label>
15+
<label>
16+
请求时间:
17+
<input type="range" v-model="requestTime" min="100" max="3000" step="100" />
18+
{{ requestTime }}ms
19+
</label>
20+
<label>
21+
延迟显示:
22+
<input type="range" v-model="delay" min="0" max="1000" step="100" />
23+
{{ delay }}ms
24+
</label>
25+
<label>
26+
最小显示时间:
27+
<input type="range" v-model="minDisplayTime" min="0" max="2000" step="100" />
28+
{{ minDisplayTime }}ms
29+
</label>
30+
</div>
31+
</div>
32+
33+
<div class="result-display">
34+
<div class="status-info">
35+
<div class="status-item">
36+
<span>加载状态 (loading):</span>
37+
<span :class="{ 'status-active': loading }">{{ loading ? '加载中' : '空闲' }}</span>
38+
</div>
39+
<div class="status-item">
40+
<span>延迟加载状态 (loadingDelayed):</span>
41+
<span :class="{ 'status-active': loadingDelayed }">{{ loadingDelayed ? '显示' : '隐藏' }}</span>
42+
</div>
43+
</div>
44+
<div class="loading-container">
45+
<div v-if="isOptimized ? loadingDelayed : loading" class="loading-spinner"></div>
46+
<div v-else class="content">{{ content }}, 本次 loading 显示时间: {{ useTime }}ms</div>
47+
</div>
48+
</div>
49+
</div>
50+
</div>
51+
52+
<div class="code-section">
53+
<h2>代码示例</h2>
54+
<pre><code>
55+
import { ref, onUnmounted } from 'vue'
56+
import { useDelayedLoading } from '@utopia/vueuse'
57+
58+
// 创建加载状态
59+
const loading = ref(false)
60+
61+
// 配置延迟加载
62+
const { loadingDelayed, cleanup } = useDelayedLoading(loading, {
63+
delay: 300, // 延迟300ms显示加载
64+
minDisplayTime: 500 // 最小显示500ms
65+
})
66+
67+
// 模拟异步请求
68+
const fetchData = async () => {
69+
loading.value = true
70+
try {
71+
await new Promise(resolve => setTimeout(resolve, 1000))
72+
// 获取数据...
73+
} finally {
74+
loading.value = false
75+
}
76+
}
77+
78+
// 在组件卸载时清理计时器
79+
onUnmounted(() => {
80+
cleanup()
81+
})
82+
</code></pre>
83+
</div>
84+
85+
<div class="explanation">
86+
<h2>说明</h2>
87+
<ul>
88+
<li><strong>加载延迟 (delay)</strong>: 当异步操作开始时,等待指定时间后再显示加载动画,避免闪烁</li>
89+
<li><strong>最小显示时间 (minDisplayTime)</strong>: 一旦显示加载动画,确保它至少显示指定的时间,避免过快消失造成的视觉混乱</li>
90+
<li><strong>清理功能 (cleanup)</strong>: 在组件卸载时调用,防止内存泄漏</li>
91+
</ul>
92+
</div>
93+
</div>
94+
</template>
95+
96+
<script setup lang="ts">
97+
import { ref, onUnmounted, watch } from 'vue'
98+
import { useDelayedLoading } from '@utopia-utils/vueuse'
99+
100+
// 配置参数
101+
const delay = ref(300)
102+
const minDisplayTime = ref(500)
103+
const requestTime = ref(3000)
104+
105+
const useTime = ref(0)
106+
107+
// 状态
108+
const loading = ref(false)
109+
const content = ref('数据已加载')
110+
/** 是否优化 loading 的显示 */
111+
const isOptimized = ref(true)
112+
113+
// 使用延迟加载Hook的函数和值
114+
let { loadingDelayed, cleanup } = useDelayedLoading(loading, {
115+
delay: delay,
116+
minDisplayTime: minDisplayTime
117+
})
118+
119+
let now = Date.now()
120+
watch(loadingDelayed, (newVal) => {
121+
if (newVal) {
122+
now = Date.now()
123+
} else {
124+
useTime.value = Date.now() - now
125+
}
126+
})
127+
128+
// 模拟异步请求
129+
const startLoading = async () => {
130+
loading.value = true
131+
content.value = '加载中...'
132+
133+
try {
134+
// 模拟API请求
135+
await new Promise(resolve => setTimeout(resolve, requestTime.value))
136+
content.value = `数据已更新 (${new Date().toLocaleTimeString()})`
137+
} catch (error) {
138+
content.value = '加载失败'
139+
} finally {
140+
loading.value = false
141+
}
142+
}
143+
144+
// 组件卸载时清理
145+
onUnmounted(cleanup)
146+
</script>
147+
148+
<style scoped>
149+
.delayed-loading-demo {
150+
max-width: 800px;
151+
margin: 0 auto;
152+
padding: 20px;
153+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
154+
}
155+
156+
h1, h2 {
157+
color: #2c3e50;
158+
}
159+
160+
.demo-section, .code-section, .explanation {
161+
margin-bottom: 30px;
162+
border: 1px solid #eaeaea;
163+
border-radius: 8px;
164+
padding: 20px;
165+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
166+
background-color: white;
167+
}
168+
169+
.demo-card {
170+
display: flex;
171+
flex-direction: column;
172+
gap: 20px;
173+
}
174+
175+
.demo-controls {
176+
display: flex;
177+
flex-direction: column;
178+
gap: 15px;
179+
}
180+
181+
button {
182+
padding: 10px 16px;
183+
background-color: #3498db;
184+
color: white;
185+
border: none;
186+
border-radius: 4px;
187+
cursor: pointer;
188+
font-size: 16px;
189+
transition: background-color 0.3s;
190+
}
191+
192+
button:hover:not(:disabled) {
193+
background-color: #2980b9;
194+
}
195+
196+
button:disabled {
197+
background-color: #95a5a6;
198+
cursor: not-allowed;
199+
}
200+
201+
.loading-config {
202+
display: flex;
203+
flex-direction: column;
204+
gap: 10px;
205+
background-color: #f8f9fa;
206+
padding: 15px;
207+
border-radius: 4px;
208+
}
209+
210+
label {
211+
display: flex;
212+
align-items: center;
213+
gap: 10px;
214+
}
215+
216+
input[type="range"] {
217+
flex: 1;
218+
}
219+
220+
.result-display {
221+
border: 1px dashed #ddd;
222+
border-radius: 4px;
223+
padding: 20px;
224+
min-height: 200px;
225+
display: flex;
226+
flex-direction: column;
227+
gap: 20px;
228+
}
229+
230+
.status-info {
231+
display: flex;
232+
justify-content: space-between;
233+
flex-wrap: wrap;
234+
gap: 10px;
235+
border-bottom: 1px solid #eee;
236+
padding-bottom: 10px;
237+
}
238+
239+
.status-item {
240+
display: flex;
241+
align-items: center;
242+
gap: 8px;
243+
}
244+
245+
.status-active {
246+
color: #2ecc71;
247+
font-weight: bold;
248+
}
249+
250+
.loading-container {
251+
display: flex;
252+
justify-content: center;
253+
align-items: center;
254+
min-height: 120px;
255+
}
256+
257+
.loading-spinner {
258+
width: 50px;
259+
height: 50px;
260+
border: 5px solid rgba(0, 0, 0, 0.1);
261+
border-radius: 50%;
262+
border-top-color: #3498db;
263+
animation: spin 1s ease-in-out infinite;
264+
}
265+
266+
@keyframes spin {
267+
to { transform: rotate(360deg); }
268+
}
269+
270+
.content {
271+
text-align: center;
272+
font-size: 18px;
273+
}
274+
275+
pre {
276+
background-color: #f8f9fa;
277+
padding: 15px;
278+
border-radius: 4px;
279+
overflow-x: auto;
280+
font-family: 'Courier New', Courier, monospace;
281+
font-size: 14px;
282+
line-height: 1.5;
283+
}
284+
285+
code {
286+
color: #16a085;
287+
}
288+
289+
.explanation ul {
290+
line-height: 1.6;
291+
}
292+
293+
.explanation li {
294+
margin-bottom: 10px;
295+
}
296+
</style>

example/src/views/UseFakeProgressView.vue

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
<script setup lang='ts'>
2+
import { ref } from 'vue'
23
import { useFakeProgress } from '@utopia-utils/vueuse'
34
5+
const state = ref<'idle' | 'loading' | 'success' | 'error'>('idle')
6+
47
const { progress, startProgress, stopProgress, incProgress, doneProgress, resetProgress, setProgress } = useFakeProgress()
58
69
function start() {
710
startProgress()
8-
// 假设某个异步操作完成后,设置进度为100%
9-
setTimeout(() => {
11+
request()
12+
}
13+
14+
// 模拟异步请求
15+
const request = async () => {
16+
state.value = 'loading'
17+
18+
try {
19+
// 模拟API请求
20+
await new Promise(resolve => setTimeout(resolve, 30 * 1000))
21+
state.value = 'success'
1022
doneProgress()
11-
}, 4000)
23+
} catch (error) {
24+
state.value = 'error'
25+
}
1226
}
1327
</script>
1428

@@ -24,6 +38,9 @@ function start() {
2438
<div>
2539
Current progress: {{ progress }}
2640
</div>
41+
<div>
42+
接口请求状态: <span :style="{ color: state === 'success' ? 'green' : '' }">{{ state }}</span>
43+
</div>
2744

2845
<div class="buttons">
2946
<button @click="start">

0 commit comments

Comments
 (0)