PullRefresh.js 6.5 KB

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