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

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

 作者:潘某人SEO
376

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

假进度条

很多网页的进度条基本上就是装装样子的,基本上页面打开了就显示加载到了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
公众号
潘某人SEO 关注我每天学习SEO优化相关知识... 470篇原创内容
潘某SEO 公众号
申明:以上内容仅代表个人观点,仅供学习参考 本站图片来源于CC0协议或已获得VRF授权的图库站点 版权申明:本文为博主原创,未经授权任何个人或组织单位不得复制、转载、摘编以及其它形式的应用! 本文地址:https://www.chateach.com/it/javascript/1032jindu
相关文章
  • 如何修改重置mysql密码

    重置mysql密码

    人生处处充满着意外,忘记了mysql密码无法登陆数据库,就需要重置mysql密码,今天以linux环境下的mysql数据密码的重置。大致的原理就是设置跳过数据库密码,然后设置登陆密码,在恢复数据登陆权限。

    378
    • 重置mysql密码
  • css鼠标悬停变色:超链接字体随鼠标悬停颜色改变实现

    css鼠标悬停变色

    css设置超链接鼠标悬停字体上时字体变颜色,css设置鼠标悬停变色布局。鼠标悬停字体上文字变色,通常针对超链接锚文本字体颜色改变,使用了伪类:hover。

    681
    • css鼠标悬停变色
  • Sudo 本地提权漏洞修复

    Sudo提权漏洞,

    Unix和Linux系统Sudo 本地提权漏洞修复,国外研究团队发现sudo堆溢出漏洞(CVE-2021-3156),漏洞隐藏十年之久,普通用户可以通过利用此漏洞,在默认配置的 sudo 主机上获取root权限。

    897
    • Sudo提权漏洞
  • 如何解决Vue中mounted不能获取到data

    mounted获取data

    Vue中使用mounted时,无法获取到data的原因是,this无法指向data中的数据。在mounted生命周期中this指向的是window对象而不是Vue对象,所以真正找的是window对象下的data,但是window下没有data,所以就报错了。

    1168
    • mounted获取data
  • Spring Boot 如何解决跨域问题

    SpringBoot跨域

    SpringBoot 如何解决跨域问题方法,CORS全称Cross-Origin Resource Sharing,意为跨域资源共享。当一个资源去访问另一个不同域名或者同域名不同端口的资源时,就会发出跨域请求。如果此时另一个资源不允许其进行跨域资源访问,那么访问的那个资源就会遇到跨域问题。

    326
    • SpringBoot跨域
  • springboot网站搭建部署详细流程

    springboot

    linux环境如何搭建java框架springboot,为大家演示一种快速简单的搭建springboot的方法。由于springboot是java的众多框架之一,因此需要部署好java的运行环境,即服务器安装好jdk18以及tomcat3,注意版本的兼容性。

    815
    • springboot
  • 如何监听客户端的网络速度及质量

    网络质量

    在实际形况中,站点及应用可以满足绝对的流畅性,但是用户的网络环境千变万化,尤其是移动端用户,这种情况情况下页面加载速度的瓶颈完全就取决于用户的网络环境。通过浏览器的 Network Information API 接口中提供的Navigator对象的connection属性,来评估用户的连接速度以及设备所处的网络类型。

    197
    • 网络质量
  • JavaScript == 与 === 区别

    == 与 === 区别

    js中==和===的区别 ==和===的区别和一些比较规则: == 在比较类型不同的变量时,会进行数据类型转化,将二者转换成数据类型相同的变量,再进行比较。对于 string、number 等基础类型,== 和 === 是有区别的 a)不同类型间比较,== 之比较 "转化成同一类型后的值" 看 "值" 是否相等,=== 如果类型不同,其结果就是不等。

    418
    • == 与 === 区别
  • SpringBoot--Thymeleaf日期格式处理

    Thymeleaf,日期格式

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

    373
    • Thymeleaf
    • 日期格式
  • laravel url路由中存在双斜杠(//)造成404问题

    laravel路由双斜杠

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

    1212
    • laravel路由双斜杠
  • Laravel的简介及其安装方法

    Laravel安装方法

    linux下使用composer的方式安装laravel 9.x版本的方法,及laravel的简介,Laravel是一套简洁、优雅的PHP Web开发框架,它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。具有了一套高级的PHP ActiveRecord实现 -- Eloquent ORM。

    777
    • Laravel安装方法
  • linux系统下使用Vue CLI脚手架安装vue3

    Vue CLI,vue3

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

    961
    • Vue CLI
    • vue3
  • 使用nginx部署vue项目

    nginx部署vue项目

    使用nginx部署vue项目,​node自己本身可以作为服务器进行驱动,但是node本身对文件的处理能力并不是很好,所以当我们的生产环境中应尽量使用nginx来处理静态的资源以及反向代理,同时也解决了node分布式以及负载均衡的相关问题。

    669
    • nginx部署vue项目
  • centos下修改ssh端口

    ssh端口,

    服务器如何修改默认的ssh端口,修改ssh默认端口是非常有必要的可以保证登陆的安全性。

    766
    • ssh端口
  • HTML marquee标签如何制作滚动文字

    marquee标签,滚动文字

    在HTML页面中可以使用marquee标签实现页面文字滚动效果,给大家分享的是有关HTML代码如何制作滚动文字的内容。HTML技术中使文字滚动的方法是使用双标签marquee。

    737
    • marquee标签
    • 滚动文字
  • php如何检测mysql数据库连接正确

    mysql链接检测

    php下如何测试MYSQL数据库是否连接正常。分享一个快速检测数据库连接正确的方法,选择一张有数据的表,打印其中的一个参数。能够正常的输入数据库数据那么链接觉得没有问题。

    774
    • mysql链接检测
  • 解决百度UEditor富文本编辑器回车追加P标签问题

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

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

    1620
    • UEditor
    • 百度富文本编辑器
    • p标签
  • Vue 中使用 localStorage 详解

    localStorage,Vue

    什么是localStorage,与cookie的区别是什么,localStorage的生存期、数据结构、域名限制、浏览器支持;localStorage常用方法,存储数据setItem、读取数据getItem、修改数据、删除数据。

    843
    • localStorage
    • Vue
-- 这已经是底线了,看看别的把! --