SwipeCell.mjs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { createVNode as _createVNode } from "vue";
  2. import { ref, reactive, computed, defineComponent } from "vue";
  3. import { clamp, isDef, numericProp, preventDefault, callInterceptor, createNamespace, makeNumericProp } from "../utils/index.mjs";
  4. import { useRect, useClickAway, useEventListener } from "@vant/use";
  5. import { useTouch } from "../composables/use-touch.mjs";
  6. import { useExpose } from "../composables/use-expose.mjs";
  7. const [name, bem] = createNamespace("swipe-cell");
  8. const swipeCellProps = {
  9. name: makeNumericProp(""),
  10. disabled: Boolean,
  11. leftWidth: numericProp,
  12. rightWidth: numericProp,
  13. beforeClose: Function,
  14. stopPropagation: Boolean
  15. };
  16. var stdin_default = defineComponent({
  17. name,
  18. props: swipeCellProps,
  19. emits: ["open", "close", "click"],
  20. setup(props, {
  21. emit,
  22. slots
  23. }) {
  24. let opened;
  25. let lockClick;
  26. let startOffset;
  27. const root = ref();
  28. const leftRef = ref();
  29. const rightRef = ref();
  30. const state = reactive({
  31. offset: 0,
  32. dragging: false
  33. });
  34. const touch = useTouch();
  35. const getWidthByRef = (ref2) => ref2.value ? useRect(ref2).width : 0;
  36. const leftWidth = computed(() => isDef(props.leftWidth) ? +props.leftWidth : getWidthByRef(leftRef));
  37. const rightWidth = computed(() => isDef(props.rightWidth) ? +props.rightWidth : getWidthByRef(rightRef));
  38. const open = (side) => {
  39. state.offset = side === "left" ? leftWidth.value : -rightWidth.value;
  40. if (!opened) {
  41. opened = true;
  42. emit("open", {
  43. name: props.name,
  44. position: side
  45. });
  46. }
  47. };
  48. const close = (position) => {
  49. state.offset = 0;
  50. if (opened) {
  51. opened = false;
  52. emit("close", {
  53. name: props.name,
  54. position
  55. });
  56. }
  57. };
  58. const toggle = (side) => {
  59. const offset = Math.abs(state.offset);
  60. const THRESHOLD = 0.15;
  61. const threshold = opened ? 1 - THRESHOLD : THRESHOLD;
  62. const width = side === "left" ? leftWidth.value : rightWidth.value;
  63. if (width && offset > width * threshold) {
  64. open(side);
  65. } else {
  66. close(side);
  67. }
  68. };
  69. const onTouchStart = (event) => {
  70. if (!props.disabled) {
  71. startOffset = state.offset;
  72. touch.start(event);
  73. }
  74. };
  75. const onTouchMove = (event) => {
  76. if (props.disabled) {
  77. return;
  78. }
  79. const {
  80. deltaX
  81. } = touch;
  82. touch.move(event);
  83. if (touch.isHorizontal()) {
  84. lockClick = true;
  85. state.dragging = true;
  86. const isEdge = !opened || deltaX.value * startOffset < 0;
  87. if (isEdge) {
  88. preventDefault(event, props.stopPropagation);
  89. }
  90. state.offset = clamp(deltaX.value + startOffset, -rightWidth.value, leftWidth.value);
  91. }
  92. };
  93. const onTouchEnd = () => {
  94. if (state.dragging) {
  95. state.dragging = false;
  96. toggle(state.offset > 0 ? "left" : "right");
  97. setTimeout(() => {
  98. lockClick = false;
  99. }, 0);
  100. }
  101. };
  102. const onClick = (position = "outside") => {
  103. emit("click", position);
  104. if (opened && !lockClick) {
  105. callInterceptor(props.beforeClose, {
  106. args: [{
  107. name: props.name,
  108. position
  109. }],
  110. done: () => close(position)
  111. });
  112. }
  113. };
  114. const getClickHandler = (position, stop) => (event) => {
  115. if (stop) {
  116. event.stopPropagation();
  117. }
  118. onClick(position);
  119. };
  120. const renderSideContent = (side, ref2) => {
  121. const contentSlot = slots[side];
  122. if (contentSlot) {
  123. return _createVNode("div", {
  124. "ref": ref2,
  125. "class": bem(side),
  126. "onClick": getClickHandler(side, true)
  127. }, [contentSlot()]);
  128. }
  129. };
  130. useExpose({
  131. open,
  132. close
  133. });
  134. useClickAway(root, () => onClick("outside"), {
  135. eventName: "touchstart"
  136. });
  137. useEventListener("touchmove", onTouchMove, {
  138. target: root
  139. });
  140. return () => {
  141. var _a;
  142. const wrapperStyle = {
  143. transform: `translate3d(${state.offset}px, 0, 0)`,
  144. transitionDuration: state.dragging ? "0s" : ".6s"
  145. };
  146. return _createVNode("div", {
  147. "ref": root,
  148. "class": bem(),
  149. "onClick": getClickHandler("cell", lockClick),
  150. "onTouchstartPassive": onTouchStart,
  151. "onTouchend": onTouchEnd,
  152. "onTouchcancel": onTouchEnd
  153. }, [_createVNode("div", {
  154. "class": bem("wrapper"),
  155. "style": wrapperStyle
  156. }, [renderSideContent("left", leftRef), (_a = slots.default) == null ? void 0 : _a.call(slots), renderSideContent("right", rightRef)])]);
  157. };
  158. }
  159. });
  160. export {
  161. stdin_default as default
  162. };