/** 下拉菜单模块 date:2020-05-04 License By http://easyweb.vip */ layui.define(['jquery'], function (exports) { var $ = layui.jquery; var openClass = 'dropdown-open'; var disableClass = 'dropdown-disabled'; var noScrollClass = 'dropdown-no-scroll'; var shadeClass = 'dropdown-menu-shade'; var dropdownClass = 'dropdown-menu'; var dropNavClass = 'dropdown-menu-nav'; var hoverClass = 'dropdown-hover'; var fixedClass = 'fixed'; var noShadeClass = 'no-shade'; var animClass = 'layui-anim layui-anim-upbit'; var popAnimClass = 'layui-anim layui-anim-fadein'; var dropDirect = ['bottom-left', 'bottom-right', 'bottom-center', 'top-left', 'top-right', 'top-center', 'left-top', 'left-bottom', 'left-center', 'right-top', 'right-bottom', 'right-center']; if ($('#ew-css-dropdown').length <= 0) { layui.link(layui.cache.base + 'dropdown/dropdown.css'); } var dropdown = { // 绑定事件 init: function () { // 点击触发 $(document).off('click.dropdown').on('click.dropdown', '.' + dropdownClass + '>*:first-child', function (event) { var $drop = $(this).parent(); if (!$drop.hasClass(hoverClass)) { if ($drop.hasClass(openClass)) { $drop.removeClass(openClass); } else { dropdown.hideAll(); dropdown.show($(this).parent().find('.' + dropNavClass)); } } event.stopPropagation(); }); // 点击任何位置关闭所有 $(document).off('click.dropHide').on('click.dropHide', function (event) { dropdown.hideAll(); }); // 点击下拉菜单内容部分不关闭 $(document).off('click.dropNav').on('click.dropNav', '.' + dropNavClass, function (event) { event.stopPropagation(); }); // hover触发 var timer, lastDrop, hoverSelector = '.' + dropdownClass + '.' + hoverClass; $(document).off('mouseenter.dropdown').on('mouseenter.dropdown', hoverSelector, function (event) { if (lastDrop && lastDrop == event.currentTarget) { clearTimeout(timer); } dropdown.show($(this).find('.' + dropNavClass)); }); $(document).off('mouseleave.dropdown').on('mouseleave.dropdown', hoverSelector, function (event) { lastDrop = event.currentTarget; timer = setTimeout(function () { $(event.currentTarget).removeClass(openClass); }, 300); }); // 分离式绑定 $(document).off('click.dropStand').on('click.dropStand', '[data-dropdown]', function (event) { dropdown.showFixed($(this)); event.stopPropagation(); }); // 无限级子菜单 var hoverNavSelector = '.' + dropNavClass + ' li'; $(document).off('mouseenter.dropdownNav').on('mouseenter.dropdownNav', hoverNavSelector, function (event) { $(this).children('.dropdown-menu-nav-child').addClass(animClass); $(this).addClass('active'); }); $(document).off('mouseleave.dropdownNav').on('mouseleave.dropdownNav', hoverNavSelector, function (event) { $(this).removeClass('active'); $(this).find('li.active').removeClass('active'); }); // 气泡确认弹窗 $(document).off('click.popconfirm').on('click.popconfirm', '.dropdown-menu-nav [btn-cancel]', function (event) { dropdown.hideAll(); event.stopPropagation(); }); }, // 点击菜单关闭 openClickNavClose: function () { $(document).off('click.dropNavA').on('click.dropNavA', '.' + dropNavClass + '>li>a', function (event) { dropdown.hideAll(); $(this).parentsUntil('.' + dropdownClass).last().parent().removeClass(openClass); event.stopPropagation(); }); }, // 关闭所有 hideAll: function () { $('.' + dropdownClass).removeClass(openClass); // 隐藏分离式菜单 $('.' + dropNavClass + '.' + fixedClass).addClass('layui-hide'); // 隐藏分离式菜单 $('.' + shadeClass).remove(); // 移除遮罩层 $('body').removeClass(noScrollClass); // 移除禁止页面滚动 $('.dropdown-fix-parent').removeClass('dropdown-fix-parent'); $('[data-dropdown]').removeClass(openClass); }, // 展开非分离式下拉菜单 show: function ($dropNav) { if ($dropNav && $dropNav.length > 0 && !$dropNav.hasClass(disableClass)) { if ($dropNav.hasClass('dropdown-popconfirm')) { $dropNav.removeClass(animClass); $dropNav.addClass(popAnimClass); } else { $dropNav.removeClass(popAnimClass); $dropNav.addClass(animClass); } var position; // 获取位置 for (var i = 0; i < dropDirect.length; i++) { if ($dropNav.hasClass('dropdown-' + dropDirect[i])) { position = dropDirect[i]; break; } } if (!position) { // 没有设置位置添加默认位置 $dropNav.addClass('dropdown-' + dropDirect[0]); position = dropDirect[0]; } dropdown.forCenter($dropNav, position); $dropNav.parent('.' + dropdownClass).addClass(openClass); return position; } return false; }, // 展开分离式菜单 showFixed: function ($trigger) { var $dropNav = $($trigger.data('dropdown')), position; if (!$dropNav.hasClass('layui-hide')) { dropdown.hideAll(); // 已经展开则隐藏 return; } dropdown.hideAll(); // 已经展开则隐藏 position = dropdown.show($dropNav); // 获取弹出位置 if (position) { $dropNav.addClass(fixedClass); // 设置为固定定位 $dropNav.removeClass('layui-hide'); // 显示下拉菜单 var topLeft = dropdown.getTopLeft($trigger, $dropNav, position); // 计算坐标 topLeft = dropdown.checkPosition($dropNav, $trigger, position, topLeft); // 是否溢出屏幕 $dropNav.css(topLeft); // 设置坐标 $('body').addClass(noScrollClass); // 禁止页面滚动 var hideShade = ($trigger.attr('no-shade') == 'true'); // 是否隐藏遮罩层 $('body').append('
'); // 添加遮罩层 // 重置父元素z-index $trigger.parentsUntil('body').each(function () { var zIndex = $(this).css('z-index'); if (/[0-9]+/.test(zIndex)) { $(this).addClass('dropdown-fix-parent'); } }); $trigger.addClass(openClass); } }, // 解决绝对定位因动画导致平移失效 forCenter: function ($dropNav, position) { if (!$dropNav.hasClass(fixedClass)) { var wTrigger = $dropNav.parent().outerWidth(), hTrigger = $dropNav.parent().outerHeight(); var wDrop = $dropNav.outerWidth(), hDrop = $dropNav.outerHeight(); var pParts = position.split('-'), dropSide = pParts[0], dropPosition = pParts[1]; // 显示方向 if ((dropSide == 'top' || dropSide == 'bottom') && dropPosition == 'center') { $dropNav.css('left', (wTrigger - wDrop) / 2); } if ((dropSide == 'left' || dropSide == 'right') && dropPosition == 'center') { $dropNav.css('top', (hTrigger - hDrop) / 2); } } }, // 计算固定定位坐标 getTopLeft: function ($trigger, $dropdown, position) { var widthTrigger = $trigger.outerWidth(); var heightTrigger = $trigger.outerHeight(); var widthDropdown = $dropdown.outerWidth(); var heightDropdown = $dropdown.outerHeight(); var topTrigger = $trigger.offset().top - $(document).scrollTop(); var leftTrigger = $trigger.offset().left; var rightTrigger = leftTrigger + widthTrigger; var top = 0, left = 0; var positionParts = position.split('-'); var anchorSide = positionParts[0]; // 箭头位置 var anchorPosition = positionParts[1]; // 箭头方向 if (anchorSide == 'top' || anchorSide == 'bottom') { heightDropdown += 8; // 加上margin距离 switch (anchorPosition) { case 'left': left = leftTrigger; break; case 'center': left = leftTrigger - widthDropdown / 2 + widthTrigger / 2; break; case 'right': left = rightTrigger - widthDropdown; } } if (anchorSide == 'left' || anchorSide == 'right') { widthDropdown += 8; // 加上margin距离 switch (anchorPosition) { case 'top': top = topTrigger + heightTrigger - heightDropdown; break; case 'center': top = topTrigger - heightDropdown / 2 + heightTrigger / 2; break; case 'bottom': top = topTrigger; } } switch (anchorSide) { case 'top': top = topTrigger - heightDropdown; break; case 'right': left = leftTrigger + widthTrigger; break; case 'bottom': top = topTrigger + heightTrigger; break; case 'left': left = leftTrigger - widthDropdown; } return {top: top, left: left, right: 'auto', bottom: 'auto'}; }, // 检查是否溢出屏幕 checkPosition: function ($dropNav, $trigger, position, topLeft) { var aps = position.split('-'); if ('bottom' == aps[0]) { if ((topLeft.top + $dropNav.outerHeight()) > dropdown.getPageHeight()) { topLeft = dropdown.getTopLeft($trigger, $dropNav, 'top-' + aps[1]); $dropNav.removeClass('dropdown-' + position); $dropNav.addClass('dropdown-top-' + aps[1]); } } else if ('top' == aps[0]) { if (topLeft.top < 0) { topLeft = dropdown.getTopLeft($trigger, $dropNav, 'bottom-' + aps[1]); $dropNav.removeClass('dropdown-' + position); $dropNav.addClass('dropdown-bottom-' + aps[1]); } } return topLeft; }, // 获取浏览器高度 getPageHeight: function () { return document.documentElement.clientHeight || document.body.clientHeight; }, // 获取浏览器宽度 getPageWidth: function () { return document.documentElement.clientWidth || document.body.clientWidth; } }; dropdown.init(); exports('dropdown', dropdown); });