mirror of https://github.com/layui/layui
feat(dropdown): 支持同时打开多个
parent
3c64d33e6e
commit
e731de490c
|
@ -95,6 +95,8 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
var that = this;
|
var that = this;
|
||||||
that.index = ++dropdown.index;
|
that.index = ++dropdown.index;
|
||||||
that.config = $.extend({}, that.config, dropdown.config, options);
|
that.config = $.extend({}, that.config, dropdown.config, options);
|
||||||
|
that.stopClickOutsideEvent = $.noop;
|
||||||
|
that.stopResizeEvent = $.noop;
|
||||||
that.init();
|
that.init();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -307,18 +309,25 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
mainElem.attr('style', options.style);
|
mainElem.attr('style', options.style);
|
||||||
|
|
||||||
// 辞旧迎新
|
// 辞旧迎新
|
||||||
that.remove(dropdown.thisId);
|
that.remove(options.id);
|
||||||
options.target.append(mainElem);
|
options.target.append(mainElem);
|
||||||
options.elem.data(MOD_INDEX_OPENED, true); // 面板已打开的标记
|
options.elem.data(MOD_INDEX_OPENED, true); // 面板已打开的标记
|
||||||
|
|
||||||
// 遮罩
|
// 遮罩
|
||||||
var shade = options.shade ? ('<div class="'+ STR_ELEM_SHADE +'" style="'+ ('z-index:'+ (mainElem.css('z-index')-1) +'; background-color: ' + (options.shade[1] || '#000') + '; opacity: ' + (options.shade[0] || options.shade)) +'"></div>') : '';
|
var shade = options.shade ? ('<div class="'+ STR_ELEM_SHADE +'" style="'+ ('z-index:'+ (mainElem.css('z-index')-1) +'; background-color: ' + (options.shade[1] || '#000') + '; opacity: ' + (options.shade[0] || options.shade)) +'"></div>') : '';
|
||||||
mainElem.before(shade);
|
var shadeElem = $(shade);
|
||||||
|
// 处理移动端点击穿透问题
|
||||||
|
if(clickOrMousedown === 'touchstart'){
|
||||||
|
shadeElem.on(clickOrMousedown, function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
mainElem.before(shadeElem);
|
||||||
|
|
||||||
// 如果是鼠标移入事件,则鼠标移出时自动关闭
|
// 如果是鼠标移入事件,则鼠标移出时自动关闭
|
||||||
if(options.trigger === 'mouseenter'){
|
if(options.trigger === 'mouseenter'){
|
||||||
mainElem.on('mouseenter', function(){
|
mainElem.on('mouseenter', function(){
|
||||||
clearTimeout(thisModule.timer);
|
clearTimeout(that.timer);
|
||||||
}).on('mouseleave', function(){
|
}).on('mouseleave', function(){
|
||||||
that.delayRemove();
|
that.delayRemove();
|
||||||
});
|
});
|
||||||
|
@ -326,7 +335,6 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
}
|
}
|
||||||
|
|
||||||
that.position(); // 定位坐标
|
that.position(); // 定位坐标
|
||||||
dropdown.thisId = options.id; // 当前打开的面板 id
|
|
||||||
|
|
||||||
// 阻止全局事件
|
// 阻止全局事件
|
||||||
mainElem.find('.layui-menu').on(clickOrMousedown, function(e){
|
mainElem.find('.layui-menu').on(clickOrMousedown, function(e){
|
||||||
|
@ -369,6 +377,11 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
resizeObserver.observe(mainElem[0], that.position.bind(that));
|
resizeObserver.observe(mainElem[0], that.position.bind(that));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
that.stopClickOutsideEvent();
|
||||||
|
that.stopResizeEvent();
|
||||||
|
that.stopClickOutsideEvent = that.onClickOutside();
|
||||||
|
that.stopResizeEvent = that.autoUpdatePosition();
|
||||||
|
|
||||||
// 组件打开完毕的事件
|
// 组件打开完毕的事件
|
||||||
typeof options.ready === 'function' && options.ready(mainElem, options.elem);
|
typeof options.ready === 'function' && options.ready(mainElem, options.elem);
|
||||||
};
|
};
|
||||||
|
@ -410,6 +423,12 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
delete dropdown.thisId;
|
delete dropdown.thisId;
|
||||||
typeof options.close === 'function' && options.close(options.elem);
|
typeof options.close === 'function' && options.close(options.elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 关闭后移除全局事件
|
||||||
|
that.stopResizeEvent();
|
||||||
|
that.stopResizeEvent = $.noop;
|
||||||
|
that.stopClickOutsideEvent();
|
||||||
|
that.stopClickOutsideEvent = $.noop;
|
||||||
};
|
};
|
||||||
|
|
||||||
Class.prototype.normalizedDelay = function(){
|
Class.prototype.normalizedDelay = function(){
|
||||||
|
@ -427,9 +446,9 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
Class.prototype.delayRemove = function(){
|
Class.prototype.delayRemove = function(){
|
||||||
var that = this;
|
var that = this;
|
||||||
var options = that.config;
|
var options = that.config;
|
||||||
clearTimeout(thisModule.timer);
|
clearTimeout(that.timer);
|
||||||
|
|
||||||
thisModule.timer = setTimeout(function(){
|
that.timer = setTimeout(function(){
|
||||||
that.remove();
|
that.remove();
|
||||||
}, that.normalizedDelay().hide);
|
}, that.normalizedDelay().hide);
|
||||||
};
|
};
|
||||||
|
@ -449,7 +468,7 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
|
|
||||||
// 触发元素事件
|
// 触发元素事件
|
||||||
options.elem.off(trigger).on(trigger, function(e) {
|
options.elem.off(trigger).on(trigger, function(e) {
|
||||||
clearTimeout(thisModule.timer);
|
clearTimeout(that.timer);
|
||||||
that.e = e;
|
that.e = e;
|
||||||
|
|
||||||
// 主面板是否已打开
|
// 主面板是否已打开
|
||||||
|
@ -458,7 +477,7 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
// 若为鼠标移入事件,则延迟触发
|
// 若为鼠标移入事件,则延迟触发
|
||||||
if (isMouseEnter) {
|
if (isMouseEnter) {
|
||||||
if (!opened) {
|
if (!opened) {
|
||||||
thisModule.timer = setTimeout(function(){
|
that.timer = setTimeout(function(){
|
||||||
that.render();
|
that.render();
|
||||||
}, that.normalizedDelay().show);
|
}, that.normalizedDelay().show);
|
||||||
}
|
}
|
||||||
|
@ -483,6 +502,60 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击面板外部时的事件
|
||||||
|
* @returns {() => void} 返回一个函数,用于取消事件
|
||||||
|
*/
|
||||||
|
Class.prototype.onClickOutside = function () {
|
||||||
|
var that = this;
|
||||||
|
var options = that.config;
|
||||||
|
var isCtxMenu = options.trigger === 'contextmenu';
|
||||||
|
var isTopElem = lay.isTopElem(options.elem[0]);
|
||||||
|
|
||||||
|
return lay.onClickOutside(
|
||||||
|
that.mainElem[0],
|
||||||
|
function (e) {
|
||||||
|
// 点击面板外部时的事件
|
||||||
|
if(typeof options.onClickOutside === 'function'){
|
||||||
|
var shouldClose = options.onClickOutside(e);
|
||||||
|
if(shouldClose === false) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
that.remove();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignore: (isCtxMenu || isTopElem) ? null : [options.elem[0]],
|
||||||
|
event: clickOrMousedown,
|
||||||
|
capture: false,
|
||||||
|
detectIframe: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 窗口大小变化时自动更新位置
|
||||||
|
* @returns {() => void} 返回一个函数,用于取消事件
|
||||||
|
*/
|
||||||
|
Class.prototype.autoUpdatePosition = function(){
|
||||||
|
var that = this;
|
||||||
|
var options = that.config;
|
||||||
|
|
||||||
|
var handleResize = function(){
|
||||||
|
if(that.mainElem && (!that.mainElem[0] || !that.mainElem.is(':visible'))) return;
|
||||||
|
if(options.trigger === 'contextmenu'){
|
||||||
|
that.remove();
|
||||||
|
} else {
|
||||||
|
that.position();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on('resize.lay_dropdown_resize', handleResize)
|
||||||
|
|
||||||
|
return function(){
|
||||||
|
$(window).off('resize.lay_dropdown_resize')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 记录所有实例
|
// 记录所有实例
|
||||||
thisModule.that = {}; // 记录所有实例对象
|
thisModule.that = {}; // 记录所有实例对象
|
||||||
|
|
||||||
|
@ -535,78 +608,6 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) {
|
||||||
var _WIN = $(window);
|
var _WIN = $(window);
|
||||||
var _DOC = $(document);
|
var _DOC = $(document);
|
||||||
|
|
||||||
// 自适应定位
|
|
||||||
_WIN.on('resize', function(){
|
|
||||||
if(!dropdown.thisId) return;
|
|
||||||
var that = thisModule.getThis(dropdown.thisId);
|
|
||||||
if(!that) return;
|
|
||||||
|
|
||||||
if((that.mainElem && !that.mainElem[0]) || !$('.'+ STR_ELEM)[0]){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = that.config;
|
|
||||||
|
|
||||||
if(options.trigger === 'contextmenu'){
|
|
||||||
that.remove();
|
|
||||||
} else {
|
|
||||||
that.position();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 点击任意处关闭
|
|
||||||
lay(_DOC).on(clickOrMousedown, function(e){
|
|
||||||
if(!dropdown.thisId) return;
|
|
||||||
var that = thisModule.getThis(dropdown.thisId)
|
|
||||||
if(!that) return;
|
|
||||||
|
|
||||||
var options = that.config;
|
|
||||||
var isTopElem = lay.isTopElem(options.elem[0]);
|
|
||||||
var isCtxMenu = options.trigger === 'contextmenu';
|
|
||||||
|
|
||||||
// 若触发的是绑定的元素,或者属于绑定元素的子元素,则不关闭
|
|
||||||
// 满足条件:当前绑定的元素是 body document,或者是鼠标右键事件时,忽略绑定元素
|
|
||||||
var isTriggerTarget = !(isTopElem || isCtxMenu) && (options.elem[0] === e.target || options.elem.find(e.target)[0]);
|
|
||||||
var isPanelTarget = that.mainElem && (e.target === that.mainElem[0] || that.mainElem.find(e.target)[0]);
|
|
||||||
if(isTriggerTarget || isPanelTarget) return;
|
|
||||||
// 处理移动端点击穿透问题
|
|
||||||
if(e.type === 'touchstart' && options.elem.data(MOD_INDEX_OPENED)){
|
|
||||||
$(e.target).hasClass(STR_ELEM_SHADE) && e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击 dropdown 外部时的回调
|
|
||||||
if(typeof options.onClickOutside === 'function'){
|
|
||||||
var shouldClose = options.onClickOutside(e);
|
|
||||||
if(shouldClose === false) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
that.remove();
|
|
||||||
}, lay.passiveSupported ? { passive: false} : false);
|
|
||||||
|
|
||||||
// onClickOutside 检测 iframe
|
|
||||||
_WIN.on('blur', function(e){
|
|
||||||
if(!dropdown.thisId) return;
|
|
||||||
var that = thisModule.getThis(dropdown.thisId)
|
|
||||||
if(!that) return;
|
|
||||||
if(!that.config.elem.data(MOD_INDEX_OPENED)) return;
|
|
||||||
|
|
||||||
setTimeout(function(){
|
|
||||||
if(document.activeElement && document.activeElement.tagName === 'IFRAME'
|
|
||||||
&& that.mainElem && that.mainElem[0]
|
|
||||||
&& that.mainElem[0].contains && !that.mainElem[0].contains(document.activeElement)
|
|
||||||
){
|
|
||||||
// 点击 dropdown 外部时的回调
|
|
||||||
if(typeof that.config.onClickOutside === 'function'){
|
|
||||||
var shouldClose = that.config.onClickOutside(e.originalEvent);
|
|
||||||
if(shouldClose === false) return;
|
|
||||||
}
|
|
||||||
that.remove();
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
})
|
|
||||||
|
|
||||||
// 基础菜单的静态元素事件
|
// 基础菜单的静态元素事件
|
||||||
var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li';
|
var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li';
|
||||||
_DOC.on('click', ELEM_LI, function(e){
|
_DOC.on('click', ELEM_LI, function(e){
|
||||||
|
|
Loading…
Reference in New Issue