这几个月做了个项目,在此对一些问题做一个记录。
项目是前后端分离的,前端用的 npm+webpack。
问题:由于系统某页面数据量过大或网络较差等原因,导致页面还未完全加载出来,但按钮已被加载时(js还未就绪),点击按钮会报错。
根据系统情况,解决方案:每个页面加载的时候,在header上方加一个动态的进度条,同时通过css样式在页面上覆盖一个透明的背景,使页面在加载完成前不可点击。页面完全加载后,进度条到100%,然后消失。
方案实施:
1. 在项目的系统公用文件里建一个loading.js文件,内容如下:
module.exports = function() {
class Process {
constructor(prop) {
this.timer = null;
this.id = `_${(new Date().getTime() + parseInt(Math.random() *1000)).toString(32)}_loading`;
this.maskId = `_${(new Date().getTime() + parseInt(Math.random() *1000)).toString(32)}_mask`;
this.loading();
}
loading() {
var html = [
`<div id="${this.maskId}" class="loading-mask js-loading-mask"></div>`,
`<div id="${this.id}" class="loading-line-wrap js-loading-line-wrap"><p class="loading-line"></p></div>`
], dis = [80, 90], speed = [1, 3], _dis = this.random(dis), _speed =this.random(speed);
$('body').append(html.join(''));
this.play(_dis, _speed, 0);
}
random(option) {
var times = option[1] - option[0],
offset = option[0];
return Math.random() * times + offset;
}
play(dis, speed, num) {
if(num + speed >= dis) {
this.timer && clearTimeout(this.timer);
}else {
num = num + speed;
}
$(`#${this.id}`).css({width: `${num}%`});
this.timer = setTimeout(()=>{
this.play(dis, speed, num);
}, 50);
}
completeLoading() {
this.timer && clearTimeout(this.timer);
$(`#${this.id}`).stop().animate({width: '100%'}, ()=> {
$(`#${this.id}`).remove();
$(`#${this.maskId}`).remove();
})
}
}
return new Process();
}
2. 在系统公用的样式文件common.scss里加上透明背景及进度条样式,内容如下:
.loading-mask{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: 0;
filter:alpha(opacity=0);
}
.loading-line-wrap{
position: fixed;
top: 0;
left: 0;
width: 0;
height: 2px;
background: #2aa7ff;
z-index: 100000;
}
3. 在系统的 main.js文件(系统的入口文件)引入 loading.js并做处理。下面省略了一些不相关的代码。有//*********的为此次新增代码。
import loading from './common-component/loading/loading.js';//*********
/**此处省略部分代码**/
let ajaxObj = {}, ajaxSend = {};//*********
$.ajaxSetup({//*********
cache: false,//*********
beforeSend: function(a, b, c, d){//*********
if(ajaxObj[`_${decodeURIComponent(this.url)}`]) {//*********
delete ajaxObj[`_${decodeURIComponent(this.url)}`];//*********
}//*********
ajaxObj[`_${decodeURIComponent(this.url)}`] = loading();//*********
}//*********
});//*********
const router = new Router(routes).configure({
notfound: () => {
alert('错误链接!');
},
before: () => {
$("div[id^=easytip-div-main],div.flatpickr-calendar").remove();
let token = Util.getCookie('token');
// 每个路径初始化商品分类
window.goodsClassify = null;
ajaxObj = {};//*********
$('.js-loading-line-wrap,.js-loading-mask').remove();//*********
$(".classify-dialog").remove();
if(!token && location.hash.indexOf('/login') < 0){
window.location.href = '/login.html'
return false;
}
chageText();
checkCurrentManager(function () {
detailFun();
});
},
after:() =>{
sessionStorage.removeItem('funcBtn');
Object.keys(ajaxSend).map(key=>{//*********
ajaxSend[key].abort();//*********
});//*********
ajaxSend = {};//*********
}
});
router.init();
//初始化默认路由
if(!Util.getRouter()){
Util.linkTo('/');
}
// header文字切换
function chageText() {
let hashCode = window.location.hash,
$pageTitle = $("#js-page-title"),
$text = $pageTitle.find('.js-header-title'),
text = '点击收起菜单';
if(hashCode == '#/home-page') {
text = 'Hi,欢迎登录xx系统,xxxxxxxx!';
}else {
if($('body').hasClass('hide-menu')) {
text = '点击展开菜单';
}
}
$text.text(text);
}
function clearLoading(key) {//*********
if(ajaxObj[`_${decodeURIComponent(st.url)}`]) {//*********
ajaxObj[`_${decodeURIComponent(st.url)}`].completeLoading();//*********
delete ajaxObj[`_${st.url}`];//*********
}//*********
}//*********
/**
* Desc: 用户未登录统一拦截模块.
*/
$(document).ajaxComplete(function(e,xhr,st){
var status = xhr.status;
if(ajaxObj[`_${decodeURIComponent(st.url)}`]) {//*********
ajaxObj[`_${decodeURIComponent(st.url)}`].completeLoading();//*********
delete ajaxObj[`_${st.url}`];//*********
}//*********
if(ajaxSend[`_${decodeURIComponent(st.url)}`]) {//*********
delete ajaxSend[`_${decodeURIComponent(st.url)}`];//*********
}//*********
if(status == 401 ){//用户未登录 则删除token跳转登录
Util.deleteCookie("token",document.domain);
sessionStorage.clear();
window.location.href = '/login.html';
}
}).ajaxSend(function(e,xhr,st){//*********
ajaxSend[`_${decodeURIComponent(st.url)}`] = xhr;//*********
});
function checkCurrentManager(callback) {//检查当前操作员密码状态
$.ajax({
type:'post',
url:API.checkCurrentManager,
// async:false,
success:function(msg){
if(msg.success){
callback ? callback() : null;
let name = ((msg.result || {}).status || {}).name;
if((msg.result || {}).firstTimeLoginFlag) {//首次登录,强制修改密码
window.location.href = '/#/modify-pwd?flag=1';
}else {
if(name == 'NORMAL'){//正常
}else if(name == 'PASSWORD_INVALIDATE'){//密码失效
$(".passwordTi").addClass('hide');
$(".passwordDesc,.passwordStatus").removeClass('hide');
Util.linkTo('/modify-pwd');
}else if(name == 'NEED_MODIFY_PASSWORD'){//需要修改密码
$(".passwordDesc,.passwordStatus").addClass('hide');
$(".passwordTi").removeClass('hide');
}
}
}else{
Util.alertMessage(msg.error);
}
}
});
}
function detailFun() {
let hashCode = window.location.href;
if(hashCode.indexOf('detail') > -1){
$("#js-toggle-menu").html('Hi,欢迎登录xx系统,xxxxxxxx!')
$("#js-page-title,.js-container-left,.content").css({marginLeft:0});
$("#js-menu,.header-logo").css({display:'none'});
}
}