首页 >  编程教程 >  javascript >  正文

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

 作者:潘某人SEO
1038

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

假进度条

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

程序逻辑思路

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

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

代码实现

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

进度条

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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

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

如何获取资源的比例

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

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

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

// 更新进度条
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);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

上述代码就实现了,获取资源总数以及资源加载完成的数量,然后每当一个资源加载完成,就会触发‘load’事件,更新对应progress标签的value值。
当然我们不一定需要获取所有的资源,可以在第8行代码选择获取哪些类型。

存在的问题

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

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

成果展示,完整代码

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

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>
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
77
78
79
80
81
82
申明:以上内容仅代表个人观点,仅供学习参考 本站图片来源于站点原创或CC0协议图库站点或已获得VRF授权的图库站点 版权申明:本文为博主原创,未经授权任何个人或组织单位不得复制、转载、摘编以及其它形式的应用! 本文地址:https://www.chateach.com/it/javascript/1032jindu
相关文章
  • laravel如何封装函数全局调用

    laravel函数封装

    laravel如何封装函数,实现全局调用。我们就拿PHPAnalysis分词程序作为例子来演示下。PHPAnalysis分词程序使用居于unicode的词库,使用反向匹配模式分词,理论上兼容编码更广泛,并且对utf-8编码尤为方便。

    1467
    • laravel函数封装
  • Springboot如何生成cookie,获取cookie信息

    Springboot,cookie

    Springboot如何生成cookie,获取cookie信息,cookie就是一个小体积的键值对,格式:key=value;客户端和服务器端,通常使用http协议来进行数据传输,而http协议是无状态的。也就是客户端向同一个服务器端发送的第一次Request和第二次Request,是没有关联的。需要cookie来保存一些用户信息,每次向相同的域名(domian)和路径(path)发送Request时都会携带cookie。

    678
    • Springboot
    • cookie
  • Java实现哈希加解密(HmacSHA1、HmacMD5、HmacSHA256、HmacSHA512)

    Java哈希加解密

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

    1610
    • Java哈希加解密
  • OpenSSL 拒绝服务漏洞修复教程

    OpenSSL 拒绝服务漏洞

    OpenSSL 拒绝服务漏洞修复及版本升级教程。2020年12月08日,OpenSSL官方发布安全公告,披露CVE-2020-1971 OpenSSL GENERAL_NAME_cmp 拒绝服务漏洞。EDIPARTYNAME时,由于GENERAL_NAME_cmp函数未能正确处理,从而导致空指针引用,并可能导致拒绝服务。

    906
    • OpenSSL 拒绝服务漏洞
  • vue 如何监听滚动至底部

    vue触底监听

    vue如何实现触底判断,实现无限加载等功能。当我们需要实现无限加载的时候,即实现瀑布流的功能的时候,核心就是监听页面的滚动事件,当滚动触底的时候去请求加载数据,既可以实现无限加载下拉。

    1176
    • vue触底监听
  • SpringBoot中的异常处理的详细教程

    SpringBoot,异常处理

    SpringBoot中的异常处理的详细教程,处理用户请求出现运行时异常时直接响应给用户的是一个错误界面,对于用户的使用体验不友好。什么是全局异常处理机制,用来解决整个系统中任意一个控制器抛出异常时的统一处理入口,如何使用全局异常处理类 implements HandlerExceptionResolver,之后重写接口中的resolveException方法。

    792
    • SpringBoot
    • 异常处理
  • php简介

    什么是php

    PHP即“超文本预处理器”,是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。利于学习

    1152
    • 什么是php
  • Java字符串的替换replace()、replaceFirst()和replaceAll()

    java,字符串

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

    533
    • java
    • 字符串
  • JavaScript简介

    JavaScript简介

    JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript

    1448
    • JavaScript简介
  • laravel url路由中存在双斜杠(//)造成404问题

    laravel路由双斜杠

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

    1622
    • laravel路由双斜杠
  • SpringBoot——Thymeleaf中的条件判断

    Thymeleaf

    SpringBoot——Thymeleaf中的条件判断(th:if、th:unless、th:switch、th:case),th:if、th:unless、th:switch、th:case 这几个属性,其实和JSP里面的那些标签都是类似的,含义就可以理解为Java语言中的if、else、switch-case这些条件判断一样,所以这里就不再详细叙述了,下面就直接给出例子!!!

    1371
    • Thymeleaf
  • 网站本地服务器搭建

    centos系统安装

    网站搭建第一步本地服务器的架设centos系统安装,对于刚接触网站编程的小伙伴不要先急着去购买服务器,当然土豪请随意。我们可以现在自己电脑上本地搭建一个虚拟服务器环境来运行,可以检测下自己是不是真的能力去搭建一个网站。

    841
    • centos系统安装
  • html网页如何禁止打印页面

    禁止打印页面

    html网页如何禁止打印页面方式,可以禁止打印键盘的快捷键组合,但是用户可以直接鼠标操作浏览器来实现打印;所以通过css来屏蔽打印内容的输出更加的合理有效,代码如下所示。

    1388
    • 禁止打印页面
  • Vue3 中全局引入 axios及其使用方法

    axios使用方法,Vue3

    Vue3如何安装axios,如何在全局使用axios,定义全局属性来使用axios,基本上每个页面都要使用到axios,因此在main.js中定义全局属性来实现axios告别繁杂的引用。

    668
    • axios使用方法
    • Vue3
  • 什么是css语言

    什么是css

    CSS全称为Cascading Style Sheets(层叠样式表),中文翻译为“层叠样式表”,简称CSS样式表。它是一种用来表现HTML或 XML 等文件式样的计算机语言。

    937
    • 什么是css
  • js防抖原理及其实现

    js防抖

    js防抖原理及其实现,在前端中有一些事件会频繁的触发容易造成页面卡顿,例如:window 的 resize、scroll、mousedown、mousemove、keyup、keydown等事件。js抖动的原因:短的时间内多次连续触发事件,首先会十分影响性能,同时大量运行结果被集中输出,结果之间不规律的冲突变化导致页面抖动。

    990
    • js防抖
  • linux换将下安装Composer的方法

    Composer安装

    linux换将下安装Composer的方法,对于需要使用laravel框架开发站点,安装Composer是非常有必要的,可以使得laravel的安装管理变得更加的方便快捷。

    913
    • Composer安装
  • MySQL数据库的介绍

    MySQL数据库的介绍

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

    1393
    • MySQL数据库的介绍
-- 这已经是底线了,看看别的把! --