diff --git a/docs/layer/detail/demo.md b/docs/layer/detail/demo.md index ceb39de0..43ba463c 100644 --- a/docs/layer/detail/demo.md +++ b/docs/layer/detail/demo.md @@ -88,6 +88,12 @@ +
+  
+
+

主题风格

diff --git a/docs/layer/detail/options.md b/docs/layer/detail/options.md index e5f585d5..a173a72b 100644 --- a/docs/layer/detail/options.md +++ b/docs/layer/detail/options.md @@ -397,6 +397,53 @@ layer.open({ +[btnAsync](#options.btnAsync) 2.9.12+ + + + + +
+ +异步按钮。开启之后,除 `layer.prompt` 的按钮外,按钮回调的返回值将支持 `boolean | Promise | JQueryDeferred` 类型,返回 `false` 或 `Promise.reject` 时阻止关闭。 + +注意,此时 `yes` 和 `btn1`(两者等效) 回调的默认行为发生了变化,即由触发时不关闭弹层变为关闭弹层。 + +
+ +``` +var sleep = function (time) { + return $.Deferred(function (defer) { + setTimeout(function () { + defer.resolve(); + }, time) + }) +} +// 下面以 confirm 层为例 +layer.confirm('一个询问框的示例?', { + btnAsync: true, + btn: ['确定', '关闭'] // 按钮 + }, + function (index, layero, that) { + var defer = $.Deferred(); + // 注: that.loading() 仅 btnAsync 开启后支持,参数为 boolean 类型,表示打开或关闭按钮的加载效果。 + that.loading(true); + sleep(1000).then(defer.resolve); + return defer.promise(); + } +); +``` + + +boolean + + +`false` + + + + + + [skin](#options.skin) @@ -746,7 +793,7 @@ layer.open({ layer.open({ content: '
', /** @type {(layero: JQuery, index: number) => boolean | JQueryDeferred | Promise} */ - beforeEnd: function(layero, index){ + beforeEnd: function(layero, index, that){ return $.Deferred(function(defer){ var el = layero.find('#id'); var val = el.val().trim(); @@ -914,4 +961,4 @@ layer.open({ - \ No newline at end of file + diff --git a/docs/layer/examples/btnasync.md b/docs/layer/examples/btnasync.md new file mode 100644 index 00000000..fa6affcc --- /dev/null +++ b/docs/layer/examples/btnasync.md @@ -0,0 +1,90 @@ + + + + + + + + \ No newline at end of file diff --git a/src/css/modules/layer.css b/src/css/modules/layer.css index 7d6a09ee..4ebfdfd4 100644 --- a/src/css/modules/layer.css +++ b/src/css/modules/layer.css @@ -144,6 +144,8 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;} .layui-layer-btn .layui-layer-btn0{border-color: transparent; background-color: #1E9FFF; color:#fff;} .layui-layer-btn-l{text-align: left;} .layui-layer-btn-c{text-align: center;} +.layui-layer-btn-is-loading{opacity:0.5 !important; cursor:not-allowed !important; cursor:wait !important; overflow:hidden; white-space:nowrap; -webkit-user-select: none; -ms-user-select: none;user-select: none;} +.layui-layer-btn-is-loading .layui-layer-btn-loading-icon{margin-right: 8px; font-size: 14px;} /* 定制化 */ .layui-layer-dialog{min-width: 240px;} diff --git a/src/modules/layer.js b/src/modules/layer.js index 81332f91..f6c1fb8d 100644 --- a/src/modules/layer.js +++ b/src/modules/layer.js @@ -2,7 +2,7 @@ * layer * 通用 Web 弹出层组件 */ - +//@ts-ignore ;!function(window, undefined){ "use strict"; @@ -859,6 +859,16 @@ Class.pt.move = function(){ return that; }; +Class.pt.btnLoading = function(btnElem, isLoading){ + if(isLoading){ + var loadingTpl = ''; + if(btnElem.find('.layui-layer-btn-loading-icon')[0]) return; + btnElem.addClass('layui-layer-btn-is-loading').attr({disabled: ''}).prepend(loadingTpl); + }else{ + btnElem.removeClass('layui-layer-btn-is-loading').removeAttr('disabled').find('.layui-layer-btn-loading-icon').remove(); + } +} + Class.pt.callback = function(){ var that = this, layero = that.layero, config = that.config; that.openLayer(); @@ -875,18 +885,42 @@ Class.pt.callback = function(){ // 按钮 layero.find('.'+ doms[6]).children('a').on('click', function(){ - var index = $(this).index(); - if(index === 0){ - if(config.yes){ - config.yes(that.index, layero, that); - } else if(config['btn1']){ - config['btn1'](that.index, layero, that); - } else { + var btnElem = $(this); + var index = btnElem.index(); + if(btnElem.attr('disabled')) return; + + // 若为异步按钮 + if(config.btnAsync){ + var btnCallback = index === 0 ? (config.yes || config['btn1']) : config['btn'+(index+1)]; + that.loading = function(isLoading){ + that.btnLoading(btnElem, isLoading); + } + + if(btnCallback){ + ready.promiseLikeResolve(btnCallback.call(config, that.index, layero, that)) + .then(function(result){ + if(result !== false){ + layer.close(that.index) + } + }, function(reason){ + reason !== undefined && window.console && window.console.error('layer error hint: ' + reason); + }); + }else{ layer.close(that.index); } - } else { - var close = config['btn'+(index+1)] && config['btn'+(index+1)](that.index, layero, that); - close === false || layer.close(that.index); + } else { // 普通按钮 + if(index === 0){ + if(config.yes){ + config.yes(that.index, layero, that); + } else if(config['btn1']){ + config['btn1'](that.index, layero, that); + } else { + layer.close(that.index); + } + } else { + var close = config['btn'+(index+1)] && config['btn'+(index+1)](that.index, layero, that); + close === false || layer.close(that.index); + } } }); @@ -926,7 +960,7 @@ Class.pt.callback = function(){ }); config.end && (ready.end[that.index] = config.end); - config.beforeEnd && (ready.beforeEnd[that.index] = config.beforeEnd); + config.beforeEnd && (ready.beforeEnd[that.index] = $.proxy(config.beforeEnd, config, layero, that.index, that)); }; // for ie6 恢复 select @@ -1000,6 +1034,18 @@ ready.restScrollbar = function(index){ } }; +// 类似 Promise.resolve +ready.promiseLikeResolve = function(value){ + var deferred = $.Deferred(); + + if(value && typeof value.then === 'function'){ + value.then(deferred.resolve, deferred.reject); + }else{ + deferred.resolve(value); + } + return deferred.promise(); +} + /** 内置成员 */ window.layer = layer; @@ -1307,19 +1353,7 @@ layer.close = function(index, callback){ } if(!hideOnClose && typeof ready.beforeEnd[index] === 'function'){ - // 类似 Promise.resolve - var promiseLikeResolve = function(value){ - var deferred = $.Deferred(); - - if(value && typeof value.then === 'function'){ - value.then(deferred.resolve, deferred.reject); - }else{ - deferred.resolve(value); - } - return deferred.promise(); - } - - promiseLikeResolve(ready.beforeEnd[index](layero, index)) + ready.promiseLikeResolve(ready.beforeEnd[index]()) .then(function(result){ if(result !== false){ delete ready.beforeEnd[index];