887efaa11bd09ea7af66e6f25b522a15c1b3f68bd1c1ce6ee291fb753b85d817fa61c1f68378987757887a996f3a11614fa5933aa3ba5b9cbb84a42486aff7 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { nextTick } from 'vue';
  2. import { throttle } from 'lodash-unified';
  3. import { isFunction } from '@vue/shared';
  4. import { throwError } from '../../../utils/error.mjs';
  5. import { getScrollContainer } from '../../../utils/dom/scroll.mjs';
  6. import { getOffsetTopDistance } from '../../../utils/dom/position.mjs';
  7. const SCOPE = "ElInfiniteScroll";
  8. const CHECK_INTERVAL = 50;
  9. const DEFAULT_DELAY = 200;
  10. const DEFAULT_DISTANCE = 0;
  11. const attributes = {
  12. delay: {
  13. type: Number,
  14. default: DEFAULT_DELAY
  15. },
  16. distance: {
  17. type: Number,
  18. default: DEFAULT_DISTANCE
  19. },
  20. disabled: {
  21. type: Boolean,
  22. default: false
  23. },
  24. immediate: {
  25. type: Boolean,
  26. default: true
  27. }
  28. };
  29. const getScrollOptions = (el, instance) => {
  30. return Object.entries(attributes).reduce((acm, [name, option]) => {
  31. var _a, _b;
  32. const { type, default: defaultValue } = option;
  33. const attrVal = el.getAttribute(`infinite-scroll-${name}`);
  34. let value = (_b = (_a = instance[attrVal]) != null ? _a : attrVal) != null ? _b : defaultValue;
  35. value = value === "false" ? false : value;
  36. value = type(value);
  37. acm[name] = Number.isNaN(value) ? defaultValue : value;
  38. return acm;
  39. }, {});
  40. };
  41. const destroyObserver = (el) => {
  42. const { observer } = el[SCOPE];
  43. if (observer) {
  44. observer.disconnect();
  45. delete el[SCOPE].observer;
  46. }
  47. };
  48. const handleScroll = (el, cb) => {
  49. const { container, containerEl, instance, observer, lastScrollTop } = el[SCOPE];
  50. const { disabled, distance } = getScrollOptions(el, instance);
  51. const { clientHeight, scrollHeight, scrollTop } = containerEl;
  52. const delta = scrollTop - lastScrollTop;
  53. el[SCOPE].lastScrollTop = scrollTop;
  54. if (observer || disabled || delta < 0)
  55. return;
  56. let shouldTrigger = false;
  57. if (container === el) {
  58. shouldTrigger = scrollHeight - (clientHeight + scrollTop) <= distance;
  59. } else {
  60. const { clientTop, scrollHeight: height } = el;
  61. const offsetTop = getOffsetTopDistance(el, containerEl);
  62. shouldTrigger = scrollTop + clientHeight >= offsetTop + clientTop + height - distance;
  63. }
  64. if (shouldTrigger) {
  65. cb.call(instance);
  66. }
  67. };
  68. function checkFull(el, cb) {
  69. const { containerEl, instance } = el[SCOPE];
  70. const { disabled } = getScrollOptions(el, instance);
  71. if (disabled || containerEl.clientHeight === 0)
  72. return;
  73. if (containerEl.scrollHeight <= containerEl.clientHeight) {
  74. cb.call(instance);
  75. } else {
  76. destroyObserver(el);
  77. }
  78. }
  79. const InfiniteScroll = {
  80. async mounted(el, binding) {
  81. const { instance, value: cb } = binding;
  82. if (!isFunction(cb)) {
  83. throwError(SCOPE, "'v-infinite-scroll' binding value must be a function");
  84. }
  85. await nextTick();
  86. const { delay, immediate } = getScrollOptions(el, instance);
  87. const container = getScrollContainer(el, true);
  88. const containerEl = container === window ? document.documentElement : container;
  89. const onScroll = throttle(handleScroll.bind(null, el, cb), delay);
  90. if (!container)
  91. return;
  92. el[SCOPE] = {
  93. instance,
  94. container,
  95. containerEl,
  96. delay,
  97. cb,
  98. onScroll,
  99. lastScrollTop: containerEl.scrollTop
  100. };
  101. if (immediate) {
  102. const observer = new MutationObserver(throttle(checkFull.bind(null, el, cb), CHECK_INTERVAL));
  103. el[SCOPE].observer = observer;
  104. observer.observe(el, { childList: true, subtree: true });
  105. checkFull(el, cb);
  106. }
  107. container.addEventListener("scroll", onScroll);
  108. },
  109. unmounted(el) {
  110. if (!el[SCOPE])
  111. return;
  112. const { container, onScroll } = el[SCOPE];
  113. container == null ? void 0 : container.removeEventListener("scroll", onScroll);
  114. destroyObserver(el);
  115. },
  116. async updated(el) {
  117. if (!el[SCOPE]) {
  118. await nextTick();
  119. } else {
  120. const { containerEl, cb, observer } = el[SCOPE];
  121. if (containerEl.clientHeight && observer) {
  122. checkFull(el, cb);
  123. }
  124. }
  125. }
  126. };
  127. export { CHECK_INTERVAL, DEFAULT_DELAY, DEFAULT_DISTANCE, SCOPE, InfiniteScroll as default };
  128. //# sourceMappingURL=index.mjs.map