dropdown.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /**
  2. * 下拉菜单模块
  3. * date:2019-07-12 License By http://easyweb.vip
  4. */
  5. layui.define(['jquery'], function (exports) {
  6. var $ = layui.jquery;
  7. var openClass = 'dropdown-open';
  8. var disableClass = 'dropdown-disabled';
  9. var noScrollClass = 'dropdown-no-scroll';
  10. var shadeClass = 'dropdown-menu-shade';
  11. var dropdownClass = 'dropdown-menu';
  12. var dropNavClass = 'dropdown-menu-nav';
  13. var hoverClass = 'dropdown-hover';
  14. var fixedClass = 'fixed';
  15. var noShadeClass = 'no-shade';
  16. var animClass = 'layui-anim layui-anim-upbit';
  17. 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'];
  18. layui.link(layui.cache.base + 'dropdown/dropdown.css');
  19. var dropdown = {
  20. // 绑定事件
  21. init: function () {
  22. // 点击触发
  23. $(document).off('click.dropdown').on('click.dropdown', '.' + dropdownClass + '>*:first-child', function (event) {
  24. var $drop = $(this).parent();
  25. if (!$drop.hasClass(hoverClass)) {
  26. if ($drop.hasClass(openClass)) {
  27. $drop.removeClass(openClass);
  28. } else {
  29. dropdown.show($(this).parent().find('.' + dropNavClass));
  30. }
  31. }
  32. event.stopPropagation();
  33. });
  34. // 点击任何位置关闭所有
  35. $(document).off('click.dropHide').on('click.dropHide', function (event) {
  36. dropdown.hideAll();
  37. });
  38. // 点击下拉菜单内容部分不关闭
  39. $(document).off('click.dropNav').on('click.dropNav', '.' + dropNavClass, function (event) {
  40. event.stopPropagation();
  41. });
  42. // hover触发
  43. var timer, lastDrop;
  44. $(document).off('mouseenter.dropdown').on('mouseenter.dropdown', '.' + dropdownClass + '.' + hoverClass, function (event) {
  45. if (lastDrop && lastDrop == event.currentTarget) {
  46. clearTimeout(timer);
  47. }
  48. dropdown.show($(this).find('.' + dropNavClass));
  49. });
  50. $(document).off('mouseleave.dropdown').on('mouseleave.dropdown', '.' + dropdownClass + '.' + hoverClass, function (event) {
  51. lastDrop = event.currentTarget;
  52. timer = setTimeout(function () {
  53. $(event.currentTarget).removeClass(openClass);
  54. }, 300);
  55. });
  56. // 分离式绑定
  57. $(document).off('click.dropStand').on('click.dropStand', '[data-dropdown]', function (event) {
  58. dropdown.showFixed($(this));
  59. event.stopPropagation();
  60. });
  61. },
  62. // 点击菜单关闭
  63. openClickNavClose: function () {
  64. $(document).off('click.dropNavA').on('click.dropNavA', '.' + dropNavClass + '>li>a', function (event) {
  65. dropdown.hideAll();
  66. $(this).parentsUntil('.' + dropdownClass).parent().removeClass(openClass);
  67. event.stopPropagation();
  68. });
  69. },
  70. // 关闭所有
  71. hideAll: function () {
  72. $('.' + dropdownClass).removeClass(openClass);
  73. // 隐藏分离式菜单
  74. $('.' + dropNavClass + '.' + fixedClass).addClass('layui-hide'); // 隐藏分离式菜单
  75. $('.' + shadeClass).remove(); // 移除遮罩层
  76. $('body').removeClass(noScrollClass); // 移除禁止页面滚动
  77. $('.dropdown-fixParent').removeClass('dropdown-fixParent');
  78. $('[data-dropdown]').removeClass(openClass);
  79. },
  80. // 展开非分离式下拉菜单
  81. show: function ($dropNav) {
  82. if ($dropNav && $dropNav.length > 0 && !$dropNav.hasClass(disableClass)) {
  83. $dropNav.addClass(animClass);
  84. var position; // 获取位置
  85. for (var i = 0; i < dropDirect.length; i++) {
  86. if ($dropNav.hasClass('dropdown-' + dropDirect[i])) {
  87. position = dropDirect[i];
  88. break;
  89. }
  90. }
  91. if (!position) { // 没有设置位置添加默认位置
  92. $dropNav.addClass('dropdown-' + dropDirect[0]);
  93. position = dropDirect[0];
  94. }
  95. dropdown.forCenter($dropNav, position);
  96. $dropNav.parent('.' + dropdownClass).addClass(openClass);
  97. return position;
  98. }
  99. return false;
  100. },
  101. // 展开分离式菜单
  102. showFixed: function ($trigger) {
  103. var $dropNav = $($trigger.data('dropdown')), position;
  104. if (!$dropNav.hasClass('layui-hide')) {
  105. dropdown.hideAll(); // 已经展开则隐藏
  106. return;
  107. }
  108. position = dropdown.show($dropNav); // 获取弹出位置
  109. if (position) {
  110. $dropNav.addClass(fixedClass); // 设置为固定定位
  111. $dropNav.removeClass('layui-hide'); // 显示下拉菜单
  112. var topLeft = dropdown.getTopLeft($trigger, $dropNav, position); // 计算坐标
  113. topLeft = dropdown.checkPosition($dropNav, $trigger, position, topLeft); // 是否溢出屏幕
  114. $dropNav.css(topLeft); // 设置坐标
  115. $('body').addClass(noScrollClass); // 禁止页面滚动
  116. var hideShade = ($trigger.attr('no-shade') == 'true'); // 是否隐藏遮罩层
  117. $('body').append('<div class="' + (hideShade ? (shadeClass + ' ' + noShadeClass) : shadeClass) + ' layui-anim layui-anim-fadein"></div>'); // 添加遮罩层
  118. // 重置父元素z-index
  119. $trigger.parentsUntil('body').each(function () {
  120. var zIndex = $(this).css('z-index');
  121. if (/[0-9]+/.test(zIndex)) {
  122. $(this).addClass('dropdown-fixParent');
  123. }
  124. });
  125. $trigger.addClass(openClass);
  126. }
  127. },
  128. // 解决绝对定位因动画导致平移失效
  129. forCenter: function ($dropNav, position) {
  130. if (!$dropNav.hasClass(fixedClass)) {
  131. var wTrigger = $dropNav.parent().outerWidth(), hTrigger = $dropNav.parent().outerHeight();
  132. var wDrop = $dropNav.outerWidth(), hDrop = $dropNav.outerHeight();
  133. var pParts = position.split('-'), dropSide = pParts[0], dropPosition = pParts[1]; // 显示方向
  134. if ((dropSide == 'top' || dropSide == 'bottom') && dropPosition == 'center') {
  135. $dropNav.css('left', (wTrigger - wDrop) / 2);
  136. }
  137. if ((dropSide == 'left' || dropSide == 'right') && dropPosition == 'center') {
  138. $dropNav.css('top', (hTrigger - hDrop) / 2);
  139. }
  140. }
  141. },
  142. // 计算固定定位坐标
  143. getTopLeft: function ($trigger, $dropdown, position) {
  144. var widthTrigger = $trigger.outerWidth();
  145. var heightTrigger = $trigger.outerHeight();
  146. var widthDropdown = $dropdown.outerWidth();
  147. var heightDropdown = $dropdown.outerHeight();
  148. var topTrigger = $trigger.offset().top - $(document).scrollTop();
  149. var leftTrigger = $trigger.offset().left;
  150. var rightTrigger = leftTrigger + widthTrigger;
  151. var top = 0, left = 0;
  152. var positionParts = position.split('-');
  153. var anchorSide = positionParts[0]; // 箭头位置
  154. var anchorPosition = positionParts[1]; // 箭头方向
  155. if (anchorSide == 'top' || anchorSide == 'bottom') {
  156. heightDropdown += 8; // 加上margin距离
  157. switch (anchorPosition) {
  158. case 'left':
  159. left = leftTrigger;
  160. break;
  161. case 'center':
  162. left = leftTrigger - widthDropdown / 2 + widthTrigger / 2;
  163. break;
  164. case 'right':
  165. left = rightTrigger - widthDropdown;
  166. }
  167. }
  168. if (anchorSide == 'left' || anchorSide == 'right') {
  169. widthDropdown += 8; // 加上margin距离
  170. switch (anchorPosition) {
  171. case 'top':
  172. top = topTrigger + heightTrigger - heightDropdown;
  173. break;
  174. case 'center':
  175. top = topTrigger - heightDropdown / 2 + heightTrigger / 2;
  176. break;
  177. case 'bottom':
  178. top = topTrigger;
  179. }
  180. }
  181. switch (anchorSide) {
  182. case 'top':
  183. top = topTrigger - heightDropdown;
  184. break;
  185. case 'right':
  186. left = leftTrigger + widthTrigger;
  187. break;
  188. case 'bottom':
  189. top = topTrigger + heightTrigger;
  190. break;
  191. case 'left':
  192. left = leftTrigger - widthDropdown;
  193. }
  194. return {top: top, left: left, right: 'auto', bottom: 'auto'};
  195. },
  196. // 检查是否溢出屏幕
  197. checkPosition: function ($dropNav, $trigger, position, topLeft) {
  198. var aps = position.split('-');
  199. if ('bottom' == aps[0]) {
  200. if ((topLeft.top + $dropNav.outerHeight()) > dropdown.getPageHeight()) {
  201. topLeft = dropdown.getTopLeft($trigger, $dropNav, 'top-' + aps[1]);
  202. $dropNav.removeClass('dropdown-' + position);
  203. $dropNav.addClass('dropdown-top-' + aps[1]);
  204. }
  205. } else if ('top' == aps[0]) {
  206. if (topLeft.top < 0) {
  207. topLeft = dropdown.getTopLeft($trigger, $dropNav, 'bottom-' + aps[1]);
  208. $dropNav.removeClass('dropdown-' + position);
  209. $dropNav.addClass('dropdown-bottom-' + aps[1]);
  210. }
  211. }
  212. return topLeft;
  213. },
  214. // 获取浏览器高度
  215. getPageHeight: function () {
  216. return document.documentElement.clientHeight || document.body.clientHeight;
  217. },
  218. // 获取浏览器宽度
  219. getPageWidth: function () {
  220. return document.documentElement.clientWidth || document.body.clientWidth;
  221. }
  222. };
  223. dropdown.init();
  224. exports('dropdown', dropdown);
  225. });