DropdownMenu.mjs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { createVNode as _createVNode } from "vue";
  2. import { ref, computed, defineComponent } from "vue";
  3. import { isDef, truthProp, numericProp, windowHeight, makeStringProp, makeNumericProp, createNamespace, HAPTICS_FEEDBACK } from "../utils/index.mjs";
  4. import { useId } from "../composables/use-id.mjs";
  5. import { useRect, useChildren, useClickAway, useScrollParent, useEventListener } from "@vant/use";
  6. const [name, bem] = createNamespace("dropdown-menu");
  7. const dropdownMenuProps = {
  8. overlay: truthProp,
  9. zIndex: numericProp,
  10. duration: makeNumericProp(0.2),
  11. direction: makeStringProp("down"),
  12. activeColor: String,
  13. closeOnClickOutside: truthProp,
  14. closeOnClickOverlay: truthProp
  15. };
  16. const DROPDOWN_KEY = Symbol(name);
  17. var stdin_default = defineComponent({
  18. name,
  19. props: dropdownMenuProps,
  20. setup(props, {
  21. slots
  22. }) {
  23. const id = useId();
  24. const root = ref();
  25. const barRef = ref();
  26. const offset = ref(0);
  27. const {
  28. children,
  29. linkChildren
  30. } = useChildren(DROPDOWN_KEY);
  31. const scrollParent = useScrollParent(root);
  32. const opened = computed(() => children.some((item) => item.state.showWrapper));
  33. const barStyle = computed(() => {
  34. if (opened.value && isDef(props.zIndex)) {
  35. return {
  36. zIndex: +props.zIndex + 1
  37. };
  38. }
  39. });
  40. const onClickAway = () => {
  41. if (props.closeOnClickOutside) {
  42. children.forEach((item) => {
  43. item.toggle(false);
  44. });
  45. }
  46. };
  47. const updateOffset = () => {
  48. if (barRef.value) {
  49. const rect = useRect(barRef);
  50. if (props.direction === "down") {
  51. offset.value = rect.bottom;
  52. } else {
  53. offset.value = windowHeight.value - rect.top;
  54. }
  55. }
  56. };
  57. const onScroll = () => {
  58. if (opened.value) {
  59. updateOffset();
  60. }
  61. };
  62. const toggleItem = (active) => {
  63. children.forEach((item, index) => {
  64. if (index === active) {
  65. updateOffset();
  66. item.toggle();
  67. } else if (item.state.showPopup) {
  68. item.toggle(false, {
  69. immediate: true
  70. });
  71. }
  72. });
  73. };
  74. const renderTitle = (item, index) => {
  75. const {
  76. showPopup
  77. } = item.state;
  78. const {
  79. disabled,
  80. titleClass
  81. } = item;
  82. return _createVNode("div", {
  83. "id": `${id}-${index}`,
  84. "role": "button",
  85. "tabindex": disabled ? void 0 : 0,
  86. "class": [bem("item", {
  87. disabled
  88. }), {
  89. [HAPTICS_FEEDBACK]: !disabled
  90. }],
  91. "onClick": () => {
  92. if (!disabled) {
  93. toggleItem(index);
  94. }
  95. }
  96. }, [_createVNode("span", {
  97. "class": [bem("title", {
  98. down: showPopup === (props.direction === "down"),
  99. active: showPopup
  100. }), titleClass],
  101. "style": {
  102. color: showPopup ? props.activeColor : ""
  103. }
  104. }, [_createVNode("div", {
  105. "class": "van-ellipsis"
  106. }, [item.renderTitle()])])]);
  107. };
  108. linkChildren({
  109. id,
  110. props,
  111. offset
  112. });
  113. useClickAway(root, onClickAway);
  114. useEventListener("scroll", onScroll, {
  115. target: scrollParent,
  116. passive: true
  117. });
  118. return () => {
  119. var _a;
  120. return _createVNode("div", {
  121. "ref": root,
  122. "class": bem()
  123. }, [_createVNode("div", {
  124. "ref": barRef,
  125. "style": barStyle.value,
  126. "class": bem("bar", {
  127. opened: opened.value
  128. })
  129. }, [children.map(renderTitle)]), (_a = slots.default) == null ? void 0 : _a.call(slots)]);
  130. };
  131. }
  132. });
  133. export {
  134. DROPDOWN_KEY,
  135. stdin_default as default
  136. };