如何实现提交触发的虚拟进度条,数据返回渲染后自动完成消失
虚拟进度条实现方案
1. 修正原有进度条模板的问题
你原有模板存在重复写style、样式不可见、默认展示的问题,先调整为默认隐藏、进度条填充色可见的版本:
<!-- 默认隐藏,提交后再显示 --> <div id="loadingcontainer" style="display: none; position: fixed; top: 0; left: 0; width: 100%; z-index: 9999;"> <div class="progress" style="height: 5px; margin: 0; background-color: #f0f0f0;"> <div id="myprogress" class="progress-bar" role="progressbar" style="color:#EB7051; background-color: #EB7051; width: 0%; transition: width 0.2s ease;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> </div> </div>
- 给进度条容器加了固定定位、高z-index,保证进度条始终在页面最顶部不被遮挡
- 合并了重复的style属性,修正了原来白色进度条不可见的问题,填充色使用你指定的#EB7051
- 初始宽度设为0,容器默认隐藏,符合提交后才展示的逻辑
- 加了宽度过渡动画,进度变化更顺滑
2. 虚拟进度条核心逻辑实现
虚拟进度条的核心逻辑是「加载中慢爬、完成时直接拉满」,避免真实请求未返回时进度提前走完的违和感:
- 用全局变量存储定时器,防止多次提交生成多个定时器导致进度异常加快
- 启动函数:触发时显示进度条,每100ms增加少量宽度,最多爬到80%就停住,越接近80%涨速越慢,更符合真实加载体感
- 完成函数:接口返回、页面渲染准备完成时,清除定时器,直接把进度拉到100%,停留300ms后隐藏进度条并重置宽度,给用户明确的加载完成感知
核心功能代码:
let progressTimer = null; // 启动进度条 function startProgress() { const progressBar = document.getElementById('myprogress'); const container = document.getElementById('loadingcontainer'); // 先重置状态,避免上次加载的残留 container.style.display = 'block'; progressBar.style.width = '0%'; progressBar.setAttribute('aria-valuenow', 0); // 启动定时器爬进度,最多到80%就停 progressTimer = setInterval(() => { let currentWidth = parseFloat(progressBar.style.width); if (currentWidth < 80) { // 分段设置涨速:前期快、后期慢,模拟真实加载体感 const increment = currentWidth < 30 ? 5 : currentWidth < 60 ? 3 : 1; currentWidth = Math.min(currentWidth + increment, 80); progressBar.style.width = `${currentWidth}%`; progressBar.setAttribute('aria-valuenow', currentWidth); } }, 100); } // 完成进度条 function finishProgress(callback) { clearInterval(progressTimer); const progressBar = document.getElementById('myprogress'); const container = document.getElementById('loadingcontainer'); // 直接拉到100% progressBar.style.width = '100%'; progressBar.setAttribute('aria-valuenow', 100); // 停留300ms让用户感知到加载完成 setTimeout(() => { container.style.display = 'none'; // 执行后续的渲染回调 callback && callback(); }, 300); }
3. 改造原有提交逻辑适配进度条
- 关键时序注意点:当前代码用
document.open()+document.write()重写整个页面,旧页面的DOM(包括进度条)会被直接替换,因此必须等进度条拉到100%、短暂展示后,再执行文档渲染逻辑,避免进度条提前消失。
同时把原有的嵌套异步回调改成async/await形式,保证请求流程可控,异常场景也能正确清理进度条状态:
function searchIt() { let form = document.querySelector('form') form.addEventListener('submit', async(e) => { e.preventDefault() // 提交先启动进度条 startProgress(); let urlIN = form.url.value let url = encodeURIComponent(urlIN) try { // 等待接口返回 const res = await fetch('/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url }) }) // 拿到响应文本先存下来,不直接写页面 const htmlText = await res.text(); // 进度条走完,再执行页面重写渲染 finishProgress(() => { document.open() document.write(htmlText) document.close() // 补充close方法,避免文档流异常 }) } catch (err) { console.error(err) // 请求失败也要清理进度条,避免一直卡在加载状态 clearInterval(progressTimer) document.getElementById('loadingcontainer').style.display = 'none' alert('请求失败,请稍后重试') } }) }
内容的提问来源于stack exchange,提问作者KyleUSA
相关产品推荐
相关产品推荐

