List.mjs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import { createVNode as _createVNode } from "vue";
  2. import { ref, watch, nextTick, onUpdated, onMounted, defineComponent } from "vue";
  3. import { isHidden, truthProp, makeStringProp, makeNumericProp, createNamespace } from "../utils/index.mjs";
  4. import { useRect, useScrollParent, useEventListener } from "@vant/use";
  5. import { useExpose } from "../composables/use-expose.mjs";
  6. import { useTabStatus } from "../composables/use-tab-status.mjs";
  7. import { Loading } from "../loading/index.mjs";
  8. const [name, bem, t] = createNamespace("list");
  9. const listProps = {
  10. error: Boolean,
  11. offset: makeNumericProp(300),
  12. loading: Boolean,
  13. disabled: Boolean,
  14. finished: Boolean,
  15. errorText: String,
  16. direction: makeStringProp("down"),
  17. loadingText: String,
  18. finishedText: String,
  19. immediateCheck: truthProp
  20. };
  21. var stdin_default = defineComponent({
  22. name,
  23. props: listProps,
  24. emits: ["load", "update:error", "update:loading"],
  25. setup(props, {
  26. emit,
  27. slots
  28. }) {
  29. const loading = ref(props.loading);
  30. const root = ref();
  31. const placeholder = ref();
  32. const tabStatus = useTabStatus();
  33. const scrollParent = useScrollParent(root);
  34. const check = () => {
  35. nextTick(() => {
  36. if (loading.value || props.finished || props.disabled || props.error || (tabStatus == null ? void 0 : tabStatus.value) === false) {
  37. return;
  38. }
  39. const {
  40. offset,
  41. direction
  42. } = props;
  43. const scrollParentRect = useRect(scrollParent);
  44. if (!scrollParentRect.height || isHidden(root)) {
  45. return;
  46. }
  47. let isReachEdge = false;
  48. const placeholderRect = useRect(placeholder);
  49. if (direction === "up") {
  50. isReachEdge = scrollParentRect.top - placeholderRect.top <= offset;
  51. } else {
  52. isReachEdge = placeholderRect.bottom - scrollParentRect.bottom <= offset;
  53. }
  54. if (isReachEdge) {
  55. loading.value = true;
  56. emit("update:loading", true);
  57. emit("load");
  58. }
  59. });
  60. };
  61. const renderFinishedText = () => {
  62. if (props.finished) {
  63. const text = slots.finished ? slots.finished() : props.finishedText;
  64. if (text) {
  65. return _createVNode("div", {
  66. "class": bem("finished-text")
  67. }, [text]);
  68. }
  69. }
  70. };
  71. const clickErrorText = () => {
  72. emit("update:error", false);
  73. check();
  74. };
  75. const renderErrorText = () => {
  76. if (props.error) {
  77. const text = slots.error ? slots.error() : props.errorText;
  78. if (text) {
  79. return _createVNode("div", {
  80. "role": "button",
  81. "class": bem("error-text"),
  82. "tabindex": 0,
  83. "onClick": clickErrorText
  84. }, [text]);
  85. }
  86. }
  87. };
  88. const renderLoading = () => {
  89. if (loading.value && !props.finished && !props.disabled) {
  90. return _createVNode("div", {
  91. "class": bem("loading")
  92. }, [slots.loading ? slots.loading() : _createVNode(Loading, {
  93. "class": bem("loading-icon")
  94. }, {
  95. default: () => [props.loadingText || t("loading")]
  96. })]);
  97. }
  98. };
  99. watch(() => [props.loading, props.finished, props.error], check);
  100. if (tabStatus) {
  101. watch(tabStatus, (tabActive) => {
  102. if (tabActive) {
  103. check();
  104. }
  105. });
  106. }
  107. onUpdated(() => {
  108. loading.value = props.loading;
  109. });
  110. onMounted(() => {
  111. if (props.immediateCheck) {
  112. check();
  113. }
  114. });
  115. useExpose({
  116. check
  117. });
  118. useEventListener("scroll", check, {
  119. target: scrollParent,
  120. passive: true
  121. });
  122. return () => {
  123. var _a;
  124. const Content = (_a = slots.default) == null ? void 0 : _a.call(slots);
  125. const Placeholder = _createVNode("div", {
  126. "ref": placeholder,
  127. "class": bem("placeholder")
  128. }, null);
  129. return _createVNode("div", {
  130. "ref": root,
  131. "role": "feed",
  132. "class": bem(),
  133. "aria-busy": loading.value
  134. }, [props.direction === "down" ? Content : Placeholder, renderLoading(), renderFinishedText(), renderErrorText(), props.direction === "up" ? Content : Placeholder]);
  135. };
  136. }
  137. });
  138. export {
  139. stdin_default as default,
  140. listProps
  141. };