浅谈前端实现页面加载进度条以及 nprogress.js 的实现

以前在 Vue 的项目用了 nprogress 这个插件,一直对于其如何得知加载进度充满好奇,最近又看到了「前端如何实现页面加载进度条」这个问题,今天周六恰好一探究竟。以下仅为一家之言,如有异议,欢迎指出。

前端的页面加载进度条有两种

首先不得不说,前端的页面加载进度条其实有两种,所以你得先搞清楚说的是哪一种。

第一种,进度条显示的是 前端静态资源 的加载。比如你打开一个页面,页面需要加载 js、css、img 等静态资源,那么每加载完一个资源(监听 onload 事件或者类似事件),进度条就向前滚动一下,直到加载完所有,进度条到头。

实际操作中,如果不做前置静态资源配置,基本不可能实现,因为你很难在代码中获取页面加载所需要的 js、css、img 资源,假设可以获取,还需要监听它们的 onload 事件,即使能实现这个进度条,也是一件 性价比很低 的事情,除非一个情况。

没错,这个特殊情况就是 游戏资源的加载。我们在写游戏的时候,通常需要把静态资源项目都列出来到配置中,而且,这个资源请求,一般比较耗时,这个时候,我们就需要这样一个进度条,因为前置条件也已经满足(资源已经列出),而如果只是写一个普通的页面,我们一般不会手动去列出静态资源。(具体实现我没有研究过,实际可能更加复杂,详见 这个回答

第二种情况,也是我们现在通常说的进度条加载,举个简单的例子,GitHub 中就有用到。先打开我的 GitHub 主页 https://github.com/hanzichi,然后点击 tab 中的 Stars 标签,这个时候 url 会变成 https://github.com/hanzichi?tab=stars,进度条开始加载,当页面内容切换过去的时候,进度条结束。

以上实现,其实就是 pjax 的实现,忽略掉 “p” 的部分,其实就是一个普通的 ajax。当页面发起 ajax 请求的时候,显示进度条,ajax 结束的时候,进度条到头,从而实现整个页面加载。这种情况,其实通常都会搭档 SPA 出现。

NProgress

以上第二种情况,业界有个成熟的插件 NProgress。它的 API 非常简单,NProgress.start() 表示进度条开始,NProgress.done() 表示进度条结束。

如果搭配 pjax,可以这样用:

$(document).on('pjax:start', function() { NProgress.start(); });
$(document).on('pjax:end',   function() { NProgress.done();  });

在 Vue 中,可以这样用:

router.beforeEach((to, from, next) => {
  NProgress.start()
  next()
})

router.afterEach(() => {
  NProgress.done() // 结束 Progress
})

甚至,普通的页面中也可以用,页面开始的时候 NProgress.start(),window.onload 的回调中运行 NProgress.done()

NProgress.start()NProgress.done() 过程中,进度条会不断加载,时快时慢,这个速度的控制,依赖的是什么?答案是,进度条的进度其实是假的,进度是 NProgress 自己在代码中控制的

我们可以看下 源码,调用 NProgress.start 后,会持续调用 NProgress.inc 方法,我们看下这个方法实现:

NProgress.inc = function(amount) {
  var n = NProgress.status;

  if (!n) {
    return NProgress.start();
  } else if(n > 1) {
    return;
  } else {
    if (typeof amount !== 'number') {
      if (n >= 0 && n < 0.2) { amount = 0.1; }
      else if (n >= 0.2 && n < 0.5) { amount = 0.04; }
      else if (n >= 0.5 && n < 0.8) { amount = 0.02; }
      else if (n >= 0.8 && n < 0.99) { amount = 0.005; }
      else { amount = 0; }
    }

    n = clamp(n + amount, 0, 0.994);
    return NProgress.set(n);
  }
};

代码中的 amount 就是进度条增量(0 为进度条起始值,1 为进度条终止值),可以从数值上判断,进度条增长速度是越来越慢。当进度条增长到 99.4% 的时候,就停止了,直到调用 NProgress.done() 方法。

其实,某些场景,想获取真实进度也是可以的,xhr2 其实是可以获取进度的,用 ajax 上传文件就可以持续获取进度进行展示,本文就不展开讨论了。

posted on 2018-10-20 21:32 子迟 阅读() 评论() 编辑 收藏

版权声明:本文为zichi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zichi/p/9823043.html