You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
5.5 KiB

3 months ago
  1. import { defineComponent, getCurrentInstance, inject, ref, computed, resolveComponent, openBlock, createBlock, normalizeClass, withCtx, createElementBlock, Fragment, renderList, createVNode, createTextVNode, toDisplayString, renderSlot, createCommentVNode } from 'vue';
  2. import { ElScrollbar } from '../../scrollbar/index.mjs';
  3. import { Loading } from '@element-plus/icons-vue';
  4. import { ElIcon } from '../../icon/index.mjs';
  5. import ElCascaderNode from './node2.mjs';
  6. import { CASCADER_PANEL_INJECTION_KEY } from './types.mjs';
  7. import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
  8. import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
  9. import { useLocale } from '../../../hooks/use-locale/index.mjs';
  10. import { useId } from '../../../hooks/use-id/index.mjs';
  11. const _sfc_main = defineComponent({
  12. name: "ElCascaderMenu",
  13. components: {
  14. Loading,
  15. ElIcon,
  16. ElScrollbar,
  17. ElCascaderNode
  18. },
  19. props: {
  20. nodes: {
  21. type: Array,
  22. required: true
  23. },
  24. index: {
  25. type: Number,
  26. required: true
  27. }
  28. },
  29. setup(props) {
  30. const instance = getCurrentInstance();
  31. const ns = useNamespace("cascader-menu");
  32. const { t } = useLocale();
  33. const id = useId();
  34. let activeNode = null;
  35. let hoverTimer = null;
  36. const panel = inject(CASCADER_PANEL_INJECTION_KEY);
  37. const hoverZone = ref(null);
  38. const isEmpty = computed(() => !props.nodes.length);
  39. const isLoading = computed(() => !panel.initialLoaded);
  40. const menuId = computed(() => `${id.value}-${props.index}`);
  41. const handleExpand = (e) => {
  42. activeNode = e.target;
  43. };
  44. const handleMouseMove = (e) => {
  45. if (!panel.isHoverMenu || !activeNode || !hoverZone.value)
  46. return;
  47. if (activeNode.contains(e.target)) {
  48. clearHoverTimer();
  49. const el = instance.vnode.el;
  50. const { left } = el.getBoundingClientRect();
  51. const { offsetWidth, offsetHeight } = el;
  52. const startX = e.clientX - left;
  53. const top = activeNode.offsetTop;
  54. const bottom = top + activeNode.offsetHeight;
  55. hoverZone.value.innerHTML = `
  56. <path style="pointer-events: auto;" fill="transparent" d="M${startX} ${top} L${offsetWidth} 0 V${top} Z" />
  57. <path style="pointer-events: auto;" fill="transparent" d="M${startX} ${bottom} L${offsetWidth} ${offsetHeight} V${bottom} Z" />
  58. `;
  59. } else if (!hoverTimer) {
  60. hoverTimer = window.setTimeout(clearHoverZone, panel.config.hoverThreshold);
  61. }
  62. };
  63. const clearHoverTimer = () => {
  64. if (!hoverTimer)
  65. return;
  66. clearTimeout(hoverTimer);
  67. hoverTimer = null;
  68. };
  69. const clearHoverZone = () => {
  70. if (!hoverZone.value)
  71. return;
  72. hoverZone.value.innerHTML = "";
  73. clearHoverTimer();
  74. };
  75. return {
  76. ns,
  77. panel,
  78. hoverZone,
  79. isEmpty,
  80. isLoading,
  81. menuId,
  82. t,
  83. handleExpand,
  84. handleMouseMove,
  85. clearHoverZone
  86. };
  87. }
  88. });
  89. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  90. const _component_el_cascader_node = resolveComponent("el-cascader-node");
  91. const _component_loading = resolveComponent("loading");
  92. const _component_el_icon = resolveComponent("el-icon");
  93. const _component_el_scrollbar = resolveComponent("el-scrollbar");
  94. return openBlock(), createBlock(_component_el_scrollbar, {
  95. key: _ctx.menuId,
  96. tag: "ul",
  97. role: "menu",
  98. class: normalizeClass(_ctx.ns.b()),
  99. "wrap-class": _ctx.ns.e("wrap"),
  100. "view-class": [_ctx.ns.e("list"), _ctx.ns.is("empty", _ctx.isEmpty)],
  101. onMousemove: _ctx.handleMouseMove,
  102. onMouseleave: _ctx.clearHoverZone
  103. }, {
  104. default: withCtx(() => {
  105. var _a;
  106. return [
  107. (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.nodes, (node) => {
  108. return openBlock(), createBlock(_component_el_cascader_node, {
  109. key: node.uid,
  110. node,
  111. "menu-id": _ctx.menuId,
  112. onExpand: _ctx.handleExpand
  113. }, null, 8, ["node", "menu-id", "onExpand"]);
  114. }), 128)),
  115. _ctx.isLoading ? (openBlock(), createElementBlock("div", {
  116. key: 0,
  117. class: normalizeClass(_ctx.ns.e("empty-text"))
  118. }, [
  119. createVNode(_component_el_icon, {
  120. size: "14",
  121. class: normalizeClass(_ctx.ns.is("loading"))
  122. }, {
  123. default: withCtx(() => [
  124. createVNode(_component_loading)
  125. ]),
  126. _: 1
  127. }, 8, ["class"]),
  128. createTextVNode(" " + toDisplayString(_ctx.t("el.cascader.loading")), 1)
  129. ], 2)) : _ctx.isEmpty ? (openBlock(), createElementBlock("div", {
  130. key: 1,
  131. class: normalizeClass(_ctx.ns.e("empty-text"))
  132. }, [
  133. renderSlot(_ctx.$slots, "empty", {}, () => [
  134. createTextVNode(toDisplayString(_ctx.t("el.cascader.noData")), 1)
  135. ])
  136. ], 2)) : ((_a = _ctx.panel) == null ? void 0 : _a.isHoverMenu) ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
  137. createCommentVNode(" eslint-disable-next-line vue/html-self-closing "),
  138. (openBlock(), createElementBlock("svg", {
  139. ref: "hoverZone",
  140. class: normalizeClass(_ctx.ns.e("hover-zone"))
  141. }, null, 2))
  142. ], 2112)) : createCommentVNode("v-if", true)
  143. ];
  144. }),
  145. _: 3
  146. }, 8, ["class", "wrap-class", "view-class", "onMousemove", "onMouseleave"]);
  147. }
  148. var ElCascaderMenu = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__file", "menu.vue"]]);
  149. export { ElCascaderMenu as default };
  150. //# sourceMappingURL=menu.mjs.map