List.mjs 4.1 KB

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