PullRefresh.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. var __defProp = Object.defineProperty;
  2. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  3. var __getOwnPropNames = Object.getOwnPropertyNames;
  4. var __hasOwnProp = Object.prototype.hasOwnProperty;
  5. var __export = (target, all) => {
  6. for (var name2 in all)
  7. __defProp(target, name2, { get: all[name2], enumerable: true });
  8. };
  9. var __copyProps = (to, from, except, desc) => {
  10. if (from && typeof from === "object" || typeof from === "function") {
  11. for (let key of __getOwnPropNames(from))
  12. if (!__hasOwnProp.call(to, key) && key !== except)
  13. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  14. }
  15. return to;
  16. };
  17. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  18. var stdin_exports = {};
  19. __export(stdin_exports, {
  20. default: () => stdin_default,
  21. pullRefreshProps: () => pullRefreshProps
  22. });
  23. module.exports = __toCommonJS(stdin_exports);
  24. var import_vue = require("vue");
  25. var import_vue2 = require("vue");
  26. var import_utils = require("../utils");
  27. var import_use = require("@vant/use");
  28. var import_use_touch = require("../composables/use-touch");
  29. var import_loading = require("../loading");
  30. const [name, bem, t] = (0, import_utils.createNamespace)("pull-refresh");
  31. const DEFAULT_HEAD_HEIGHT = 50;
  32. const TEXT_STATUS = ["pulling", "loosing", "success"];
  33. const pullRefreshProps = {
  34. disabled: Boolean,
  35. modelValue: Boolean,
  36. headHeight: (0, import_utils.makeNumericProp)(DEFAULT_HEAD_HEIGHT),
  37. successText: String,
  38. pullingText: String,
  39. loosingText: String,
  40. loadingText: String,
  41. pullDistance: import_utils.numericProp,
  42. successDuration: (0, import_utils.makeNumericProp)(500),
  43. animationDuration: (0, import_utils.makeNumericProp)(300)
  44. };
  45. var stdin_default = (0, import_vue2.defineComponent)({
  46. name,
  47. props: pullRefreshProps,
  48. emits: ["change", "refresh", "update:modelValue"],
  49. setup(props, {
  50. emit,
  51. slots
  52. }) {
  53. let reachTop;
  54. const root = (0, import_vue2.ref)();
  55. const track = (0, import_vue2.ref)();
  56. const scrollParent = (0, import_use.useScrollParent)(root);
  57. const state = (0, import_vue2.reactive)({
  58. status: "normal",
  59. distance: 0,
  60. duration: 0
  61. });
  62. const touch = (0, import_use_touch.useTouch)();
  63. const getHeadStyle = () => {
  64. if (props.headHeight !== DEFAULT_HEAD_HEIGHT) {
  65. return {
  66. height: `${props.headHeight}px`
  67. };
  68. }
  69. };
  70. const isTouchable = () => state.status !== "loading" && state.status !== "success" && !props.disabled;
  71. const ease = (distance) => {
  72. const pullDistance = +(props.pullDistance || props.headHeight);
  73. if (distance > pullDistance) {
  74. if (distance < pullDistance * 2) {
  75. distance = pullDistance + (distance - pullDistance) / 2;
  76. } else {
  77. distance = pullDistance * 1.5 + (distance - pullDistance * 2) / 4;
  78. }
  79. }
  80. return Math.round(distance);
  81. };
  82. const setStatus = (distance, isLoading) => {
  83. const pullDistance = +(props.pullDistance || props.headHeight);
  84. state.distance = distance;
  85. if (isLoading) {
  86. state.status = "loading";
  87. } else if (distance === 0) {
  88. state.status = "normal";
  89. } else if (distance < pullDistance) {
  90. state.status = "pulling";
  91. } else {
  92. state.status = "loosing";
  93. }
  94. emit("change", {
  95. status: state.status,
  96. distance
  97. });
  98. };
  99. const getStatusText = () => {
  100. const {
  101. status
  102. } = state;
  103. if (status === "normal") {
  104. return "";
  105. }
  106. return props[`${status}Text`] || t(status);
  107. };
  108. const renderStatus = () => {
  109. const {
  110. status,
  111. distance
  112. } = state;
  113. if (slots[status]) {
  114. return slots[status]({
  115. distance
  116. });
  117. }
  118. const nodes = [];
  119. if (TEXT_STATUS.includes(status)) {
  120. nodes.push((0, import_vue.createVNode)("div", {
  121. "class": bem("text")
  122. }, [getStatusText()]));
  123. }
  124. if (status === "loading") {
  125. nodes.push((0, import_vue.createVNode)(import_loading.Loading, {
  126. "class": bem("loading")
  127. }, {
  128. default: getStatusText
  129. }));
  130. }
  131. return nodes;
  132. };
  133. const showSuccessTip = () => {
  134. state.status = "success";
  135. setTimeout(() => {
  136. setStatus(0);
  137. }, +props.successDuration);
  138. };
  139. const checkPosition = (event) => {
  140. reachTop = (0, import_utils.getScrollTop)(scrollParent.value) === 0;
  141. if (reachTop) {
  142. state.duration = 0;
  143. touch.start(event);
  144. }
  145. };
  146. const onTouchStart = (event) => {
  147. if (isTouchable()) {
  148. checkPosition(event);
  149. }
  150. };
  151. const onTouchMove = (event) => {
  152. if (isTouchable()) {
  153. if (!reachTop) {
  154. checkPosition(event);
  155. }
  156. const {
  157. deltaY
  158. } = touch;
  159. touch.move(event);
  160. if (reachTop && deltaY.value >= 0 && touch.isVertical()) {
  161. (0, import_utils.preventDefault)(event);
  162. setStatus(ease(deltaY.value));
  163. }
  164. }
  165. };
  166. const onTouchEnd = () => {
  167. if (reachTop && touch.deltaY.value && isTouchable()) {
  168. state.duration = +props.animationDuration;
  169. if (state.status === "loosing") {
  170. setStatus(+props.headHeight, true);
  171. emit("update:modelValue", true);
  172. (0, import_vue2.nextTick)(() => emit("refresh"));
  173. } else {
  174. setStatus(0);
  175. }
  176. }
  177. };
  178. (0, import_vue2.watch)(() => props.modelValue, (value) => {
  179. state.duration = +props.animationDuration;
  180. if (value) {
  181. setStatus(+props.headHeight, true);
  182. } else if (slots.success || props.successText) {
  183. showSuccessTip();
  184. } else {
  185. setStatus(0, false);
  186. }
  187. });
  188. (0, import_use.useEventListener)("touchmove", onTouchMove, {
  189. target: track
  190. });
  191. return () => {
  192. var _a;
  193. const trackStyle = {
  194. transitionDuration: `${state.duration}ms`,
  195. transform: state.distance ? `translate3d(0,${state.distance}px, 0)` : ""
  196. };
  197. return (0, import_vue.createVNode)("div", {
  198. "ref": root,
  199. "class": bem()
  200. }, [(0, import_vue.createVNode)("div", {
  201. "ref": track,
  202. "class": bem("track"),
  203. "style": trackStyle,
  204. "onTouchstartPassive": onTouchStart,
  205. "onTouchend": onTouchEnd,
  206. "onTouchcancel": onTouchEnd
  207. }, [(0, import_vue.createVNode)("div", {
  208. "class": bem("head"),
  209. "style": getHeadStyle()
  210. }, [renderStatus()]), (_a = slots.default) == null ? void 0 : _a.call(slots)])]);
  211. };
  212. }
  213. });