Files
mixly3/common/ui/layui/extend/loading/loading.js
2024-07-19 10:16:00 +08:00

489 lines
23 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 区域/全局 loading 效果<layui组件依赖jQuery>
* @version v1.3 最新版
* @author jlx (neusofts#neusofts.com)
* @extends {jQuery.fn.loading}
* @param {String|Object=} arg1 调用方法名<均为空参则默认show其他方法toggle,hide,hideAll,destroy,destroyAll>若为一个Object参数则更新全局配置&show<返回loading>
* @param {Object=} arg2 若arg1为{String}arg2为{Object},则优先私有配置
* @property {String=''} overlayClassName 自定义遮罩层className可多个默认空String
* @property {String=''} imgClassName 自定义image的className可多个默认空String
* @property {String='#fff'} background 自定义遮罩层背景色,默认#fff
* @property {Number=0.6} opacity 自定义遮罩层的透明度默认0.6 <为0时无遮罩层>
* @property {String=''} text 自定义loading文本默认空String<非空时参考offsetTop设置>
* @property {String=''} textCss 自定义loading文本样式默认空String<高优先级>
* @property {String=''} textClassName 自定义文本的className可多个默认空String
* @property {String=''} title 自定义div、img、text的title默认空String
* @property {Number=0} offsetTop 自定义图片+文本模式的top偏移量<text为空建议不设置offsetTop>
* @property {Number=0|String=''|null} imgSrc 自定义loading图片路径默认为图片序列的0索引<0-10>可配索引或图片url路径<为null时无图片>
* @property {Function=} beforeShow 自定义loading显示前的回调默认空Function参数1=this参数2=jQuery
* @property {Function=} afterShow 自定义loading显示后的回调默认空Function参数1=this参数2=jQuery参数3=$loading
* @property {Number=19999999+1} imgZIndex 自定义图片的z-index值默认19999999+1
* @property {Number=19999999} overlayZIndex 自定义遮罩层的z-index值默认19999999
* @property {Function=} afterHide 自定义loading隐藏/销毁后的回调默认空Function参数1=this参数2=jQuery参数3=$loading(销毁时无参数3)
* @property {Function=} afterHideAll 自定义全部loading隐藏/销毁后的回调默认空Function参数1=this参数2=jQuery参数3=$loading(销毁时无参数3)
* @property {Number=600} animateTime 自定义loading显示/隐藏的动画时长 <为0时无动画>默认600
* @property {Boolean=false} clickHide 自定义单击loading遮罩层/图片/文字是否隐藏loading默认false
* @property {Boolean=false} inheritRadius 自定义遮罩层是否继承父节点的边框效果默认false
* @event hide,hideAll,destroy,destroyAll 均监听$(obj)的lay-loading(.hide | .hideAll | .destroy | .destroyAll)事件参数event, loadingObj
* @return {Object|jQuery|Object<Array>} 返回<loading | loadingArr | jQuery | Error>对象
* @example
* $('body').loading(str?: string = 'show'); // 创建/显示loading <body,html,window,document均处理为body>
* $('body|other').loading({...}); // 注:更新全局配置 + show
* $('body|other').loading('show', {...}); // 创建/显示 + 局部配置优先
* var loadingObj = $('body|other').loading('hide').show(); // 隐藏 -> 显示
* var loadingObj = $('body|other').loading('show', {afterHide: function (loadingObj, jQueryObj, $loading) {...}});
*/
(() => {
'use strict';
goog.require('path');
goog.require('layui');
goog.provide('layui.loading');
const { loading } = layui;
loading.IMG_PATH = path.join(goog.basePath, '../ui/layui/extend/loading/images');
var _ = $.extend
, W = window // BOM/DOM
, fnName = {}
, lang = {Illegal_operation: '非法操作'} // 外部语言包模块
, _toString = Object.prototype.toString
, ds = { // 外部工具模块
getTime: function (arg) {
return arg ? (+ new Date(arg)) : (+ new Date());
},
is: {
string: function (str) {
return _toString.call(str) == '[object String]';
},
number: function (num) {
return _toString.call(num) == '[object Number]';
},
plainObject: function (obj) {
if (obj === undefined) {
return false;
} else {
return _toString.call(obj) === '[object Object]';
}
},
'undefined': function (v) {
return v === undefined || v === null;
},
'function': function (fun) {
return _toString.call(fun) === '[object Function]';
}
},
loadImage: function (url, callback, error) {
if (!url) {
return callback({src: url});
}
var imgObj;
imgObj = new Image();
imgObj.src = url;
if (imgObj.complete && callback) {
return callback(imgObj);
}
imgObj.onload = function () {
imgObj.onload = null;
callback && callback(imgObj);
};
imgObj.onerror = function (e) {
imgObj.onerror = null;
error && error(e);
};
return imgObj;
}
};
_($.fn, {
loading: function () {
var nodeNames = 'BODY,HTML,#document,undefined'
, $that = !this[0] || nodeNames.indexOf(this[0].nodeName) > -1 ? $('body') : this // 多集合仅保留body对象
, isBODY = $that[0].nodeName == 'BODY'
, arg1 = arguments[0], arg2 = arguments[1]
, loadingClassName = 'lay-loading' // 注hideAll等操作的索引若冲突请自行改之
, eventNameResize = 'resize.' + loadingClassName
, eventNameClick = 'click.'+ loadingClassName +'.clickHide'
, zIndex = 19999999
, errorFn = function () {
throw new Error(lang.Illegal_operation);
}
, imgUrl = layui.loading.IMG_PATH + '/loading/loading'
, imgSrcArr = [
imgUrl + '.gif',
imgUrl + '-bars.gif'
].concat(function () { for (var arr = [], i = 0; i <= 8; i++) { arr.push(imgUrl + '-' + i + '.gif'); }; return arr; }())
, pteMethods = {
resize: function () {
if (!this || !this instanceof $) return;
var offsetTop = this.settings && (this.settings.offsetTop || 0);
var $objs = this.$this.children('.' + loadingClassName + ':visible');
var hasImgSrc = !ds.is['undefined'](this.settings.imgSrc);
var imageH = 0, $parent = {}, parentW = 0, parentH = 0, isFixed, offsetP, safariBug, parentPosition;
var isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent); // !document.documentMode;
$objs.each(function (key, divAndimg) {
$parent = $(divAndimg).parent();
parentPosition = ('fixed,relative').indexOf($parent.css('position'));
isFixed = parentPosition > -1 || $parent[0] === $(this)[0].offsetParent;
safariBug = parentPosition < 0 && $parent[0].offsetParent !== $('body')[0] && isSafari;
// console.log(parentPosition); // -1 -1
// console.log($parent[0]); // YS-in YS-in
// console.log($(this)[0].offsetParent); // body YS-in
// console.log($parent[0].offsetParent); // body YS-out
offsetP = isFixed || safariBug ? { top: 0, left: 0 } : { top: $parent[0].offsetTop, left: $parent[0].offsetLeft };
parentW = $parent.outerWidth();
parentH = $parent.outerHeight();
if ($parent[0].nodeName == 'BODY') {
if ($(divAndimg).is('div')) {
$(divAndimg).css({
width: '100%',
height: '100%',
position: 'fixed'
});
} else if ($(divAndimg).is('img')) {
imageH = $(divAndimg).height();
$(divAndimg).css({
position: 'fixed',
top: $(W).height() / 2 - $(divAndimg).height() / 2 - offsetTop,
left: $(W).width() / 2 - $(divAndimg).width() / 2
});
} else {
$(divAndimg).css({
position: 'fixed',
top: $(W).height() / 2 + (imageH ? 6 : ( - $(divAndimg).height() / 2)) + imageH / 2 - offsetTop,
left: $(W).width() / 2 - $(divAndimg).width() / 2
});
}
} else {
if ($(divAndimg).is('div')) {
$(divAndimg).css({
// width: parentW,
// height: parentH,
width: '100%',
height: '100%',
top: offsetP.top,
left: offsetP.left
});
} else if ($(divAndimg).is('img')) {
imageH = $(divAndimg).height();
$(divAndimg).css({
top: parentH / 2 - $(divAndimg).height() / 2 + offsetP.top - offsetTop,
left: parentW / 2 - $(divAndimg).width() / 2 + offsetP.left
});
} else {
imageH = hasImgSrc ? imageH : 0;
$(divAndimg).css({
top: parentH / 2 + imageH / 2 + (imageH ? 6 : ( - $(divAndimg).height() / 2)) + offsetP.top - offsetTop,
left: parentW / 2 - $(divAndimg).width() / 2 + offsetP.left
});
}
}
});
return this;
},
subsequent: function () {
var $loading = arguments[0];
var that = $loading.parent().data('loading') || this;
var time = that.settings.animateTime;
var $this = that.$this;
var fn = that.settings[arguments[1]]
var operate = arguments[2];
var method = arguments[3];
var isAuto = arguments[4];
if (arguments[1] === 'afterHideAll') {
fn = fnName.settings.afterHideAll;
}
$loading.fadeOut(time, function () {
$(this)[operate]();
});
W.setTimeout(function () {
!isAuto && fn && fn(that, $this, operate == 'hide' ? $loading : undefined);
!isAuto && $this.trigger(loadingClassName + '.' + method, that);
}, time);
return that;
}
};
fnName.settings = fnName.settings || {
'overlayClassName': '',
'imgClassName': '',
'background': '#fff',
'opacity': 0.6,
'text': '',
'textCss': '', // {}
'textClassName': '',
'title': '',
'offsetTop': 0, // img&text的top偏移量
'imgSrc': imgSrcArr[0], // 注默认以图片居中为主若img&text同时微调可设置offsetTop
'beforeShow': function () {},
'afterShow': function () {},
'imgZIndex': zIndex + 1, // text共用
'overlayZIndex': zIndex,
'afterHide': function () {},
'afterHideAll': function () {},
'animateTime': 600,
'clickHide': !1, //可配置afterHide为reload需求
'inheritRadius': false
}
var initialCss = {
'top': -zIndex,
'left': -zIndex,
'z-index': 0,
'position': 'absolute',
'padding': 'initial',
'margin': 'initial',
'border': 'initial',
'width': 'initial',
'min-width': 'initial',
'max-width': 'initial',
'height': 'initial',
'min-height': 'initial',
'max-height': 'initial',
'opacity': 'initial'
}
, overlayStyle = {
'background': '#fff',
'height': 0, // resize value
'width': 0, // resize value
'top': 0, // resize value <html除外, 子标签在body内>
'left': 0, // resize value <html除外, 子标签在body内>
'z-index': 0,
'opacity': 0,
'position': 'absolute',
'border': '1px solid transparent',
'border-radius': 0,
'padding': 'initial',
'margin': 'initial',
'border': 'initial'
}
, imageStyle = _({}, initialCss)
, textStyle = _({}, initialCss, {
'background': 'initial',
'overflow': 'initial',
'white-space': 'nowrap',
'line-height': '120%',
'text-align': 'center',
'vertical-align': 'middle'
});
function Class(options) {
if (options && options.imgSrc !== null && ds.is.number(options.imgSrc)) {
options.imgSrc = imgSrcArr[options.imgSrc]; // undefined时$.extend不覆盖默认配置
}
this.hasNewSetting = ds.is.plainObject(options);
this.$this = options.$this;
this.settings = _({}, fnName.settings, this.hasNewSetting ? options : {});
this.settings.overlayStyle = overlayStyle;
this.settings.imageStyle = imageStyle;
this.settings.textStyle = textStyle;
}
_(Class.prototype, {
show: function () {
var _this = this;
var $this = this.$this;
var settings = this.settings;
var beforeShow = settings.beforeShow;
var overlayStyle = settings.overlayStyle;
var imageStyle = settings.imageStyle;
var textStyle = settings.textStyle;
var textCss = settings.textCss || {};
var $loadingObjSingle = $this.children('.' + loadingClassName);
var hasImgSrc = !ds.is['undefined'](settings.imgSrc);
beforeShow && beforeShow(this, $this);
if (!this.hasNewSetting && $loadingObjSingle.size() > 0) {
pteMethods.subsequent.apply(this, [
$loadingObjSingle,
'afterShow',
'show',
'show'
]);
$(W).trigger(eventNameResize);
} else {
this.destroy('auto'), ds.loadImage(hasImgSrc ? settings.imgSrc : null, function (imgObj) {
// create时不考虑动画
var $overlay = $('<div></div>');
var $image = $('<img />');
var $text = $('<span></span>');
var text = $.trim(settings.text);
var overlayW = isBODY ? window.screen.availWidth : $this.outerWidth();
var overlayH = isBODY ? window.screen.availHeight : $this.outerHeight();
overlayStyle['background'] = settings['background'];
overlayStyle['z-index'] = settings['overlayZIndex'];
overlayStyle['opacity'] = settings['opacity'];
overlayStyle['height'] = overlayH;
overlayStyle['width'] = overlayW;
if (settings.inheritRadius) {
// For IE
overlayStyle['border-top-left-radius'] = $this.css('border-top-left-radius');
overlayStyle['border-top-right-radius'] = $this.css('border-top-right-radius');
overlayStyle['border-bottom-left-radius'] = $this.css('border-bottom-left-radius');
overlayStyle['border-bottom-right-radius'] = $this.css('border-bottom-right-radius');
}
imageStyle['z-index'] = settings['imgZIndex'];
textStyle['z-index'] = settings['imgZIndex'];
$overlay
.addClass(loadingClassName)
.addClass(settings.overlayClassName)
.css(overlayStyle)
.attr('title', settings.title)
.appendTo($this).hide();
imgObj.src && $image
.addClass(loadingClassName)
.addClass(settings.imgClassName)
.css(imageStyle)
.attr('src', imgObj.src)
.attr('title', settings.title)
.appendTo($this).hide();
$text
.addClass(loadingClassName)
.addClass(settings.textClassName)
.css(_({}, textStyle, textCss))
.html(text)
.attr('title', settings.title)
.appendTo($this).hide();
setTimeout(function () {
$overlay[!settings['opacity'] ? 'remove' : 'show']();
$image[!hasImgSrc ? 'remove' : 'show']();
$text[!text.length ? 'remove' : 'show']();
$(W).trigger(eventNameResize);
settings.afterShow && settings.afterShow(_this, $this);
$this.trigger(loadingClassName + '.' + 'show', _this);
}, 0.1e3);
}, function (e) {
throw new Error(e);
});
}
return {
hide: errorFn,
hideAll: errorFn,
destroy: errorFn,
destroyAll: errorFn
};
},
toggle: function () {
if (this.$this.children('.' + loadingClassName + ':visible').size() > 0) {
return this.hide();
} else {
return this.show();
}
},
hide: function () {
return pteMethods.subsequent.apply(this, [
this.$this.children('.' + loadingClassName),
'afterHide',
'hide',
'hide'
]);
},
hideAll: function () {
return pteMethods.subsequent.apply(this, [
$('.' + loadingClassName),
'afterHideAll',
'hide',
'hideAll'
]);
},
// <传入新配置/销毁后> 新建将启用最新全局配置
destroy: function (isAuto) {
return pteMethods.subsequent.apply(this, [
this.$this.children('.' + loadingClassName),
'afterHide',
'remove',
'destroy',
isAuto
]);
},
destroyAll: function () {
return pteMethods.subsequent.apply(this, [
$('.' + loadingClassName),
'afterHideAll',
'remove',
'destroyAll'
]);
}
});
// 一个{}参数:更新全局配置&show <兼容IE8>
if (ds.is.plainObject(arg1)) {
if (arg1.imgSrc) {
arg1.imgSrc = imgSrcArr[arg1.imgSrc];
}
return $that.loading('show', _(fnName.settings, arg1));
}
// arg1为string默认调用方法 & arg2默认为局部配置
if (ds.is.string(arg1) || !arg1) {
var loading = {}, loadingArr = [], rdm;
arg1 = arg1 ? arg1 : 'show';
$that.each(function (index, obj) {
if (arg2) {
arg2.$this = $(obj);
if (arg2.afterHideAll) {
fnName.settings.afterHideAll = arg2.afterHideAll;
}
} else {
arg2 = {$this: $(obj)};
}
rdm = '.rdm' + ds.getTime() + index;
loading = new Class(arg2);
$(obj).data('loading', loading);
ds.is['function'](loading[arg1]) && loading[arg1]();
loadingArr.push(loading);
// 单击div/img/text是否隐藏
$(obj).off(eventNameClick).on(eventNameClick, '.' + loadingClassName, function (e) {
loading.settings.clickHide && $(obj).data('loading').hide();
e.stopPropagation();
return false;
});
// resize监听
$(W).off(eventNameResize + rdm).on(eventNameResize + rdm, function () {
pteMethods.resize.call($(obj).data('loading') || null);
});
});
}
return loadingArr.length > 1 ? loadingArr : loadingArr[0];
}
});
return $;
})();