页面资源加载真实进度条的详细教程

相信大家经常遇到网页加载的时候半天内容不出来,也不到要等待多久,或者说有进度条但是无法反应页面的加载进度,这种用户体验还是非常差的,给站点一个真实的进度条对于用户体验还是非常友好的,一个真实的进度条可以一定程度上可以增加用户继续等待的机率。

假进度条

很多网页的进度条基本上就是装装样子的,基本上页面打开了就显示加载到了20%,然后页面开始渲染了就显示加载到了50%,加载完成之后就显示100%。这种进度条一旦网站加载一卡顿,就会出现在一个进度值半天不动,体验式非常差的。
今天潘某人SEO分享一个基于原生javascript语法不需要任何插件来实现进度条的真实加载,按照加载资源数量的控制进度条的变化,可以实现只要网站每加载完成一个资源进度条同步变化。

程序逻辑思路

基本原理是在页面添加一个progress标签,控制标签的value值来更新进度条的加载进度;而进度值通过计算页面已加载完成资源数量和总资源数的比例获取。

  • 第一步获取资源数
  • 第二步计算完成加载的资源数的比例
  • 第三步将得到加载完成的资源数的比例值更新progress标签的value值

代码实现

别看上面逻辑很简单,但是要把功能做的完美还是有单独的,这里涉及到了浏览器页面渲染相关的知识,重点在于如何知道资源的加载状态以及如何知道资源加载完成。文末结尾有完整代码示例,接下来先一个个步骤简单讲解下。

进度条

javaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
                    DOCTYPE html>
<html>
    <head>
       <title>页面资源加载进度条---潘某人SEOtitle>
       <style>
            #progressBar{
               position: fixed;
               z-index: 200;
               top: 0;
               left: 0;
               width: 100%;
               height: 3px;
               box-shadow: 1px 2px 3px #eee;
               background-color: blue;
               transition: width 1s ease-in-out;
              }
       style>
    head>
    <body>
        <progress id="progressBar" value="0" max="100"></progress>
  </body>
 </html> 

我们使用通一个progress标签作为进度条,大家可根据自己的需求来调整进度条的样式,进度条进度的变化是通过修改 progress 标签的value值实现,当value值达到和max值相等,进度条即加载完成。接下来我们需要做的就是计算页面资源加载的比例的数值来更新value值即可。

如何获取资源的比例

progress标签的value值 = 资源加载完成的数量/资源的总数,对计算结果取整。获取页面资源的数量非常简单,难点在于什么时候去获取。正确的时间应该是在dom树构建完成,就需要获取页面资源及其数量,获取早了资源会获取不全,获取晚了资源可能就加载完成的都差不多了,都会影响进度条的准确性。

javaScript
1
2
3
4
                    // 监听dom构建完成
document.addEventListener('DOMContentLoaded', function() {
    console.log("dom构建完成")
})               

要准确的把握时机,就需要监听‘DOMContentLoaded’事件,当页面dom构建完成的时候会触发此时间,此时就可以去获取页面的资源。DOM树大致可以认为的就是页面可以看到的html变迁结构,DOM树构建完成的时候,大部分资源都是没有开始加载的,这里也暗藏下了一个问题。 那么由如何知道这些资源加载的情况呢?这就需要我们将获取到资源,每个资源添加一个‘load’事件的监听,当资源加载完成的时候会被触发,将这些触发的次数累加就得到了资源加载完成的数量。

javaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
                    // 更新进度条
function updateProgress(loadedResources) {
   progress = Math.round((loadedResources / totalResources) * 100);
   console.log('加载完成度:',progress,'%')
   progressBar.value = progress;
}
//获取页面所有资源
const resources = document.querySelectorAll('img, script, link');// 获取图片、脚本和链接资源
window.totalResources = resources.length; // 获取资源总数
window.loadedResources = 0;//已加载完成的资源数
window.progress = 0;// 进度值
window.progressBar = document.getElementById('progressBar');
resources.forEach((resource) => {//遍历元素添加load监听事件
    resource.addEventListener('load', () => {
    loadedResources++;
    console.log('加载完成的资源数量:',loadedResources)
    //更新进度条的处理函数
    updateProgress(loadedResources);
});               

上述代码就实现了,获取资源总数以及资源加载完成的数量,然后每当一个资源加载完成,就会触发‘load’事件,更新对应progress标签的value值。

当然我们不一定需要获取所有的资源,可以在第8行代码选择获取哪些类型。

存在的问题

前面说到了存在一个问题,上述代码执行的时候会发现,进度条是无法达到100%的,这是因为在‘DOMContentLoaded’事件触发完成的时候已经有部分资源已经加载完成,这个主要适合浏览器页面解析渲染的原理有关,具体的大家可以去学习了解下页面的渲染的,比较复杂这里一两句讲不清。
如js脚本会阻塞dom的构建,换句话说dom构建完成的时候,部分的js脚本的加载完成,这也是导致部分元素在‘DOMContentLoaded’事件触发的时候已经加载完成的原因之一。
解决方法是通过监听页面‘readyState’状态,在页面渲染完成的时候,将进度条更新100%进度即可,由于这部分资源数量占比比较少,对于进度条体验上不会有很大的影响。考虑的太复杂也没有意义,并且进度条的展示也是要基于js和css实现的,将资源获取的时间在往前提,个人认为意义不大。

javaScript
1
2
3
4
5
6
7
                    //页面渲染完成
document.onreadystatechange = function () {
    if (document.readyState === 'complete') {
      console.log('页面加载完成');
      //执行结束进度条的函数
    }
}               

成果展示,完整代码

页面加载进度条
上图则是在潘某人SEO站点测试下来的效果,在页面构建完成之后,开始页面加载的时候就会显示进度条,随着资源的加载进度条可以非常丝滑并且反应真实页面加载进度,页面加载完成之后,进度条达到100%后消失隐藏。

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
                    <DOCTYPE html>
<html>
    <head>
       <title>页面资源加载进度条---潘某人SEOtitle>
       <style>
            #progressBar{
               position: fixed;
               z-index: 200;
               top: 0;
               left: 0;
               width: 100%;
               height: 3px;
               box-shadow: 1px 2px 3px #eee;
               background-color: blue;
               transition: width 1s ease-in-out;
              }
       style>
    head>
    <body>
        <progress id="progressBar" value="0" max="100"></progress> 
      </body>
      <script> 
      /** * @autor 潘某人SEO www.chateach.com
       * @param {String} state ---"start"开启进度条加载、“end”进度条到达100结束进度条
       */
      function changeProgress(state) {
          // 更新进度条
           function updateProgress(loadedResources) {
             progress = Math.round((loadedResources / totalResources) * 100);
              console.log('加载完成度:',progress,'%') progressBar.value = progress;
            }
             switch (state) {
                //开启进度条 case 
                "start": //获取页面所有资源
                 const resources = document.querySelectorAll('img, script, link');// 获取图片、脚本和链接资源
                  window.totalResources = resources.length; // 获取资源总数 
                  window.loadedResources = 0;//已加载完成的资源数 
                  window.progress = 0;// 进度值 
                  window.progressBar = document.getElementById('progressBar'); 
                  console.log("resources:",resources)
                   resources.forEach((resource) => {
                     //遍历元素添加load监听事件
                      resource.addEventListener('load', () => {
                         loadedResources++;
                          console.log('加载完成的资源数量:',loadedResources)
                           //更新进度条
                            updateProgress(loadedResources);
                        }); 
                     });
                  break; 
                  //结束进度条 case 
                  "end":
                   updateProgress(totalResources);
                   progressBar.style.opacity = 0;
                    setTimeout(() => { 
                     progressBar.style.display = 'none'; 
                     } , 1000);
                      break;
                  default:
                   break;
                    } 
                  } 
                  //dom构建完成
                   document.addEventListener('DOMContentLoaded', function() {
                      console.log("dom构建完成")
                       changeProgress ("start");//开启进度条 
                  }) 
                  //页面渲染完成 
                  document.onreadystatechange = function () {
                      if (document.readyState === 'complete') {
                         console.log('页面加载完成');
                          changeProgress ("end");//结束进度条,
                           } 
                  } 
   </script> 
</html>               

申明:本站内容仅代表个人观点,仅供学习参考;未经授权任何个人或组织单位不得复制、转载、摘编以及其它形式的应用!

本站文章可能使用到互联网上的资料,若对您造成困扰,请联系 kk19@foxmail.com除理

本文地址:https://www.chateach.com/it/javascript/1032jindu

相关文章

  • 解决百度UEditor富文本编辑器回车追加P标签问题

    UEditor,百度富文本编辑器,p标签

    网站的教程很多但是都比较复杂,给大家分享一个1秒可以解决百度富文本编辑器强制自动追加P标签的问题的方法。百度富UEditor富文本编辑器有一个坑就是无论你怎么修改只要你回车或者换行了就会强行追加一个P标签,会严重的影响到我们正常排版。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 2668
    • UEditor
    • 百度富文本编辑器
    • p标签
  • laravel url路由中存在双斜杠(//)造成404问题

    laravel路由双斜杠

    解决在laravel框架下,网站的首页后面加上双斜杠(//),页面显示的尽然不是首页,是一个空白的页面状态码是200,或者报404错误。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 2147
    • laravel路由双斜杠
  • Laravel邮件发送功能的实现例子

    Laravel邮件发送

    Laravel如何发送邮件呢?Laravel邮件发送功能的实现例子,从邮箱注册配置到,laravel邮件参数配置,提供纯文本邮件和富文本邮件发送两种邮件发送实例。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1804
    • Laravel邮件发送
  • lnmp环境简介

    lnmp环境简介

    LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写。L指Linux,N指Nginx,M一般指MySQL,也可以指MariaDB,P一般指PHP,也可以指Perl或Python。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1479
    • lnmp环境简介
  • Java实现哈希加解密(HmacSHA1、HmacMD5、HmacSHA256、HmacSHA512)

    Java哈希加解密

    什么是Hash,Java实现哈希加解密(HmacSHA1、HmacMD5、HmacSHA256、HmacSHA512),哈希算法不可逆,不同的源数据使用同样的哈希算法,可能会产生相同的哈希值,这被称之为碰撞率(collision rate),即使是 MD5 算法,碰撞率也非常小,小到几乎可以忽略不计。大约是 1.47*10的负29次方。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 2395
    • Java哈希加解密
  • linux系统CentOS发送邮件

    CentOS发送邮件

    如何在linux、ubuntu、centos系统中发送邮件,如定时发送网站日志,或者服务器信息状态,如何在centos系统中配置邮件发送功能。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1529
    • CentOS发送邮件
  • js中的数组元素的添加方法

    js数组添加元素

    js中的数组元素的添加方法,主要有三种方法,用索引元素添加、push( )方法、unshift()方法,push()方法在数组的尾部添加一个或多个元素,并返回数组新的长度,修改并替换了原始数组而非生成一个修改版的新数组。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 795
    • js数组添加元素
  • 原生AJAX请求实例教程

    AJAX

    如何使用原生javascript进行ajax数据请求呢?可以不重新加载整个网页通过刷新网页部分内容达到数据的更新展示。可以有效的降低对带宽的需求,提高网页的性能;Ajax有同步和异步两种实现方式。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1246
    • AJAX
  • JS中的indexOf方法

    indexOf

    indexOf()是js中内置的方法之一,它的功能大家都很熟悉:简单来说就是得到数据的索引,对于正则不熟练的人,是个很不错的方法。string中indexOf() 会将数值参数转换为字符再查询索引;number类型没有IndexOf() 可以转换为字符再使用;array中indexOf() 是严格比较

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 836
    • indexOf
  • linux系统下使用Vue CLI脚手架安装vue3

    Vue CLI,vue3

    linux系统下使用Vue CLI脚手架安装vue3。Vue 提供了一个官方的 CLI,为单页面应用 (SPA) 快速搭建繁杂的脚手架。它为现代前。端工作流提供了功能齐备的构建设置。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1643
    • Vue CLI
    • vue3
  • laravel中如何获取和设置cookie操作

    laravel ,cookie操作

    在laravel框架中 cookie的优势在于,laravel在底层会对cookie值进行加密,并且使用授权码进行签名,如果客户端修改了cookie值,那么就会失效。会比直接在php中使用cookie更加严谨安全,当然为了laravel中cookie的操作方法会与php原生的方法有所区别,虽然也可以使用php原生的方法操作,但是不推荐。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1390
    • laravel
    • cookie操作
  • springboot如何对html进行转义及恢复

    html转义,springboot

    Spring HtmlUtils把HTML编码转义,可将HTML标签互相转义,HTML中<,>,&等有特殊含义(<,>,用于链接签,&用于转义),不能直接使用。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 2440
    • html转义
    • springboot
  • java如何切分割字符串

    java,字符串

    在我们日常工作中经常遇到截取字符串的需求,这里重点介绍两种常见的java截取字符串方法。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1038
    • java
    • 字符串
  • SpringBoot--Thymeleaf日期格式处理

    Thymeleaf,日期格式

    Thymeleaf作为众多模板引擎中的一种,我最初也是对它充满了陌生,在SpringBoot如何处理时间格式,SpringBoot--Thymeleaf日期格式处理。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1128
    • Thymeleaf
    • 日期格式
  • 原生js 复制内容到剪切板代码实现

    js 复制内容,剪切板代

    有时候为了提升用户体验,比如在某些页面需要实现点击内容,将内容复制到剪切板,可以提升用户复制内容的操作效率;因此在实际操作中通过一定的事件触发复制功能是非常有意义的行为,下面是两种通过原生js实现复制内容到剪切板。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1354
    • js 复制内容
    • 剪切板代
  • laravel定义全局常量的方法

    laravel全局常量

    在 Laravel项目中有时我们会需要一些全局函数和常量,那么在laravel如何定义一个全局的常量,以及如何的使用全局常量。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1425
    • laravel全局常量
  • MySQL数据库的介绍

    MySQL数据库的介绍

    MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBM

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 1797
    • MySQL数据库的介绍
  • Java字符串的替换replace()、replaceFirst()和replaceAll()

    java,字符串

    Java字符串的替换replace()、replaceFirst()和replaceAll(),如何匹配替换字符串中的内容。

    用于表示时间的图标 一个时钟的图标,用于向用户表达后面跟着的是一个时间
    用于表示阅读次数的图标 一个类似睁开眼睛的图标,用于向用户表达后面跟着的数字是一个阅读的次数 886
    • java
    • 字符串