Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

让loading效果更线性 #2

Open
w3cmark opened this issue Dec 19, 2017 · 0 comments
Open

让loading效果更线性 #2

w3cmark opened this issue Dec 19, 2017 · 0 comments
Labels

Comments

@w3cmark
Copy link
Owner

w3cmark commented Dec 19, 2017

为了提高用户体验,在做一些比较多资源的项目,我们经常会用资源预加载的方式,一打开页面会先看到一个loading动画效果或者loading进度条,再或者加载百分比,用来暗示用户,页面资源比较多,正在加载中啦,你再等等哈,不要走喔。。。

而这里的资源预加载,就是通过js去预先请求某些资源,以备页面展示时可以直接使用,比如图片预加载,我们可能会这样实现:

var img = new Image();
img.onload = function () {
// 加载成功...
};
img.onerror = function () {
// 加载出错...
};
img.src = 'https://dummyimage.com/90x90/ddd/79c';

通过创建一个不可见的img来触发图片请求,上面演示的只是加载一张,一般情况做预加载都会有多资源才做啦,所以批量预加载只需要加入循环:

var iFileData = [//预加载图片资源
        'https://dummyimage.com/90x90/ddd/79c',
        'https://dummyimage.com/100x100/ddd/79c',
        'https://dummyimage.com/200x200/ddd/79c',
        'https://dummyimage.com/300x300/ddd/79c',
        'https://dummyimage.com/400x400/ddd/79c',
        'https://dummyimage.com/500x500/ddd/79c'
    ],
	_total = iFileData.length,
	_loaded = 0;
for(var i = 0; i < _total; i++) {
    loadImage(iFileData);
}
loadImage = function(iData){
    var img = new Image();
    img.onload = img.onerror = function () {
        _loaded++;
        checkLoadComplete();
    };
    img.src = iData;
},
checkLoadComplete = function(){
    if(_loaded == _total) {
          console.log('加载完毕');
    }
};

上面可以实现简单的预加载了,但好像没有当前加载的进度喔
下面加上一个当前加载进度的百分比:

checkLoadComplete = function(){
    var per = (_loaded/_total).toFixed(2);
    if(per > 1) {
        per = 1;
    }
    console.log('当前加载进度:' + per);
    if(_loaded == _total) {
          console.log('加载完毕');
    }
}

到这,资源预加载的功能基本就ok了,然后展示进度跟进上面的进度返回,转成数字百分比或者一个进度条就可以了。
另外,这个功能很常用,可以再做一下封装,方便使用,还可以加入其它资源的支持,比如多媒体文件?

完了?
但,这个不是本文的重点,本文的重点是线性

改良,让加载更线性

上面的预加载有个问题,体验不好。比如,你要预加载10个资源,显示的百分比就是0%,10%,20%,30%...这样10个数字的跳动,极端点,当你只有一个资源(当然这里是极端考虑,像前文说的,一个资源,你估计不会用预加载了)时,进度就是0%~100%,一下就从0跳到100了。

还有,即使是10个资源,当用户第二次打开页面,因为资源有缓存,这个loading效果就会可能一闪而过,因为有缓存加载太快了,进度都看不清就没了,体验也不好(或者即使第一次,如果用户网速很好,也会出现一闪而过)。

所以,上面的预加载体验不够好,不稳定,导致动画效果不线性。

预想的线性是怎样的呢?比如进度百分比数字,我预想的是无论多少资源,第几次打开,网速如何,都是从0%,1%,2%,3%,4%,5%,6%....这样直到100的,只有这样,数字展示才不会大幅度跳动或者进度条的宽度才不会跳跃。

那怎么达到这样的数字累加效果呢?咦?累加?那可以用定时器啊:

var _num = 0;
var _num_interval = setInterval(function(){
    _num++;
    if(_num > 99){
        clearInterval(_num_interval);
        _num = 100;
    }
    console.log(_num);
}, 50)

嗯,这样数字就不跳动啦,很线性!!从0100,每隔50毫秒加1,到100就停止,so easy

线性数字有了,但和我加载进度有毛关系?而且资源加载是会根据网速不同而不同,这50毫秒。。。假的进度,明显不行啊

第一个问题,线性数字和实际资源加载联系起来,这个还是很容易的。从第一个资源开始,就同时触发触发上面的计时器,当最后一个资源加载完而且计算到100了,就完成了预加载过程。

第二个问题,定时器的时间怎么和实际资源加载联系起来呢?定时器先根据资源数定一个初始值,加载过程通过把假的计算进度和真实的加载进度进行比较,实时调整定时器的时间,以达到尽可能的模拟实际进度:

var _time = 50;
var linearLoad = function(){
    if(_num_interval){
        clearInterval(_num_interval);
    }
    _num_interval = setInterval(function(){
        _num++;
        if(_num > 99 && (_loaded == _total)){
            clearInterval(_num_interval);
            _num = 100;
            console.log(_num);
            // 加载完毕
            console.log('加载完毕');
            return;
        }else if(_num > 99){
            clearInterval(_num_interval);
            return;
        }
        console.log(_num);
        if(_time > 1){
            adjustSpeed(_time_range);
        }
    }, _time)
},
adjustSpeed = function(range){
    //调节数字变化速度
    var per = (_loaded/_total).toFixed(2);
    if(parseInt(per*100) > _num){
        //如果实际加载速度快,提高线性数字速度
        _time = _time - range;
        _time = _time < 1 ? 1 : _time;
        linearLoad();
    }else{
        //如果实际加载慢,降低线性数字速度
        _time = _time + range;
        linearLoad();
    }
}

逻辑细节请移步测试demo:http://www.w3cmark.com/staticdemo/loading/

效果预览

loading.gif

@w3cmark w3cmark added the 总结 label Nov 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant