|
| 1 | +let hideTimer: ReturnType<typeof setTimeout> | null = null |
| 2 | +let trickleTimer: ReturnType<typeof setInterval> | null = null |
| 3 | +let el: HTMLDivElement | null = null |
| 4 | +let pending = 0 |
| 5 | +let progress = 0 |
| 6 | + |
| 7 | +function getEl(): HTMLDivElement { |
| 8 | + if (!el) { |
| 9 | + el = document.createElement('div') |
| 10 | + el.style.cssText = [ |
| 11 | + 'position:fixed', |
| 12 | + 'top:0', |
| 13 | + 'left:0', |
| 14 | + 'width:0', |
| 15 | + 'height:2px', |
| 16 | + 'background:var(--el-color-primary,#409eff)', |
| 17 | + 'z-index:9999', |
| 18 | + 'transition:width 0.3s ease,opacity 0.4s ease', |
| 19 | + 'opacity:0', |
| 20 | + ].join(';') |
| 21 | + document.body.appendChild(el) |
| 22 | + } |
| 23 | + return el |
| 24 | +} |
| 25 | + |
| 26 | +// 越接近 100% 每次前进越少,模拟真实加载感 |
| 27 | +function trickleAmount(): number { |
| 28 | + if (progress < 0.2) return 0.08 |
| 29 | + if (progress < 0.5) return 0.05 |
| 30 | + if (progress < 0.8) return 0.02 |
| 31 | + if (progress < 0.95) return 0.005 |
| 32 | + return 0 |
| 33 | +} |
| 34 | + |
| 35 | +function setProgress(n: number) { |
| 36 | + progress = Math.min(n, 0.994) |
| 37 | + getEl().style.width = (progress * 100) + '%' |
| 38 | +} |
| 39 | + |
| 40 | +function startTrickle() { |
| 41 | + if (trickleTimer) return |
| 42 | + trickleTimer = setInterval(() => setProgress(progress + trickleAmount()), 800) |
| 43 | +} |
| 44 | + |
| 45 | +function stopTrickle() { |
| 46 | + if (trickleTimer) { clearInterval(trickleTimer); trickleTimer = null } |
| 47 | +} |
| 48 | + |
| 49 | +export default { |
| 50 | + start() { |
| 51 | + pending++ |
| 52 | + if (hideTimer) { clearTimeout(hideTimer); hideTimer = null } |
| 53 | + const bar = getEl() |
| 54 | + bar.style.opacity = '1' |
| 55 | + if (progress === 0) setProgress(0.02) |
| 56 | + startTrickle() |
| 57 | + }, |
| 58 | + done() { |
| 59 | + if (pending > 0) pending-- |
| 60 | + if (pending > 0) return |
| 61 | + stopTrickle() |
| 62 | + setProgress(1) |
| 63 | + hideTimer = setTimeout(() => { |
| 64 | + getEl().style.opacity = '0' |
| 65 | + hideTimer = setTimeout(() => { |
| 66 | + getEl().style.width = '0' |
| 67 | + progress = 0 |
| 68 | + }, 400) |
| 69 | + }, 200) |
| 70 | + } |
| 71 | +} |
0 commit comments