index.mjs 3.9 KB

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