itemUtil.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. var __rest = this && this.__rest || function (s, e) {
  2. var t = {};
  3. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  4. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  5. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  6. }
  7. return t;
  8. };
  9. /**
  10. * Our algorithm have additional one ghost item
  11. * whose index as `data.length` to simplify the calculation
  12. */
  13. export const GHOST_ITEM_KEY = '__vc_ghost_item__';
  14. /**
  15. * Safari has the elasticity effect which provides negative `scrollTop` value.
  16. * We should ignore it since will make scroll animation shake.
  17. */
  18. export function alignScrollTop(scrollTop, scrollRange) {
  19. if (scrollTop < 0) {
  20. return 0;
  21. }
  22. if (scrollTop >= scrollRange) {
  23. return scrollRange;
  24. }
  25. return scrollTop;
  26. }
  27. /**
  28. * Get node `offsetHeight`. We prefer node is a dom element directly.
  29. * But if not provided, downgrade to `findDOMNode` to get the real dom element.
  30. */
  31. export function getNodeHeight(node) {
  32. return node ? node.offsetHeight : 0;
  33. }
  34. /**
  35. * Calculate the located item absolute top with whole scroll height
  36. */
  37. export function getItemAbsoluteTop(_a) {
  38. var {
  39. scrollTop
  40. } = _a,
  41. rest = __rest(_a, ["scrollTop"]);
  42. return scrollTop + getItemRelativeTop(rest);
  43. }
  44. /**
  45. * Calculate the located item related top with current window height
  46. */
  47. export function getItemRelativeTop(_ref) {
  48. let {
  49. itemIndex,
  50. itemOffsetPtg,
  51. itemElementHeights,
  52. scrollPtg,
  53. clientHeight,
  54. getItemKey
  55. } = _ref;
  56. const locatedItemHeight = itemElementHeights[getItemKey(itemIndex)] || 0;
  57. const locatedItemTop = scrollPtg * clientHeight;
  58. const locatedItemOffset = itemOffsetPtg * locatedItemHeight;
  59. return Math.floor(locatedItemTop - locatedItemOffset);
  60. }
  61. export function getCompareItemRelativeTop(_ref2) {
  62. let {
  63. locatedItemRelativeTop,
  64. locatedItemIndex,
  65. compareItemIndex,
  66. startIndex,
  67. endIndex,
  68. getItemKey,
  69. itemElementHeights
  70. } = _ref2;
  71. let originCompareItemTop = locatedItemRelativeTop;
  72. const compareItemKey = getItemKey(compareItemIndex);
  73. if (compareItemIndex <= locatedItemIndex) {
  74. for (let index = locatedItemIndex; index >= startIndex; index -= 1) {
  75. const key = getItemKey(index);
  76. if (key === compareItemKey) {
  77. break;
  78. }
  79. const prevItemKey = getItemKey(index - 1);
  80. originCompareItemTop -= itemElementHeights[prevItemKey] || 0;
  81. }
  82. } else {
  83. for (let index = locatedItemIndex; index <= endIndex; index += 1) {
  84. const key = getItemKey(index);
  85. if (key === compareItemKey) {
  86. break;
  87. }
  88. originCompareItemTop += itemElementHeights[key] || 0;
  89. }
  90. }
  91. return originCompareItemTop;
  92. }
  93. export function getScrollPercentage(_ref3) {
  94. let {
  95. scrollTop,
  96. scrollHeight,
  97. clientHeight
  98. } = _ref3;
  99. if (scrollHeight <= clientHeight) {
  100. return 0;
  101. }
  102. const scrollRange = scrollHeight - clientHeight;
  103. const alignedScrollTop = alignScrollTop(scrollTop, scrollRange);
  104. const scrollTopPtg = alignedScrollTop / scrollRange;
  105. return scrollTopPtg;
  106. }
  107. export function getElementScrollPercentage(element) {
  108. if (!element) {
  109. return 0;
  110. }
  111. return getScrollPercentage(element);
  112. }
  113. /**
  114. * Get location item and its align percentage with the scroll percentage.
  115. * We should measure current scroll position to decide which item is the location item.
  116. * And then fill the top count and bottom count with the base of location item.
  117. *
  118. * `total` should be the real count instead of `total - 1` in calculation.
  119. */
  120. function getLocationItem(scrollPtg, total) {
  121. const itemIndex = Math.floor(scrollPtg * total);
  122. const itemTopPtg = itemIndex / total;
  123. const itemBottomPtg = (itemIndex + 1) / total;
  124. const itemOffsetPtg = (scrollPtg - itemTopPtg) / (itemBottomPtg - itemTopPtg);
  125. return {
  126. index: itemIndex,
  127. offsetPtg: itemOffsetPtg
  128. };
  129. }
  130. /**
  131. * Get display items start, end, located item index. This is pure math calculation
  132. */
  133. export function getRangeIndex(scrollPtg, itemCount, visibleCount) {
  134. const {
  135. index,
  136. offsetPtg
  137. } = getLocationItem(scrollPtg, itemCount);
  138. const beforeCount = Math.ceil(scrollPtg * visibleCount);
  139. const afterCount = Math.ceil((1 - scrollPtg) * visibleCount);
  140. return {
  141. itemIndex: index,
  142. itemOffsetPtg: offsetPtg,
  143. startIndex: Math.max(0, index - beforeCount),
  144. endIndex: Math.min(itemCount - 1, index + afterCount)
  145. };
  146. }
  147. export function requireVirtual(height, itemHeight, count, virtual) {
  148. return virtual !== false && typeof height === 'number' && count * itemHeight > height;
  149. }