useScrollTo.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = useScrollTo;
  7. var _raf = _interopRequireDefault(require("../../_util/raf"));
  8. function useScrollTo(containerRef, mergedData, heights, props, getKey, collectHeight, syncScrollTop, triggerFlash) {
  9. let scroll;
  10. return arg => {
  11. // When not argument provided, we think dev may want to show the scrollbar
  12. if (arg === null || arg === undefined) {
  13. triggerFlash();
  14. return;
  15. }
  16. // Normal scroll logic
  17. _raf.default.cancel(scroll);
  18. const data = mergedData.value;
  19. const itemHeight = props.itemHeight;
  20. if (typeof arg === 'number') {
  21. syncScrollTop(arg);
  22. } else if (arg && typeof arg === 'object') {
  23. let index;
  24. const {
  25. align
  26. } = arg;
  27. if ('index' in arg) {
  28. ({
  29. index
  30. } = arg);
  31. } else {
  32. index = data.findIndex(item => getKey(item) === arg.key);
  33. }
  34. const {
  35. offset = 0
  36. } = arg;
  37. // We will retry 3 times in case dynamic height shaking
  38. const syncScroll = (times, targetAlign) => {
  39. if (times < 0 || !containerRef.value) return;
  40. const height = containerRef.value.clientHeight;
  41. let needCollectHeight = false;
  42. let newTargetAlign = targetAlign;
  43. // Go to next frame if height not exist
  44. if (height) {
  45. const mergedAlign = targetAlign || align;
  46. // Get top & bottom
  47. let stackTop = 0;
  48. let itemTop = 0;
  49. let itemBottom = 0;
  50. const maxLen = Math.min(data.length, index);
  51. for (let i = 0; i <= maxLen; i += 1) {
  52. const key = getKey(data[i]);
  53. itemTop = stackTop;
  54. const cacheHeight = heights.get(key);
  55. itemBottom = itemTop + (cacheHeight === undefined ? itemHeight : cacheHeight);
  56. stackTop = itemBottom;
  57. if (i === index && cacheHeight === undefined) {
  58. needCollectHeight = true;
  59. }
  60. }
  61. const scrollTop = containerRef.value.scrollTop;
  62. // Scroll to
  63. let targetTop = null;
  64. switch (mergedAlign) {
  65. case 'top':
  66. targetTop = itemTop - offset;
  67. break;
  68. case 'bottom':
  69. targetTop = itemBottom - height + offset;
  70. break;
  71. default:
  72. {
  73. const scrollBottom = scrollTop + height;
  74. if (itemTop < scrollTop) {
  75. newTargetAlign = 'top';
  76. } else if (itemBottom > scrollBottom) {
  77. newTargetAlign = 'bottom';
  78. }
  79. }
  80. }
  81. if (targetTop !== null && targetTop !== scrollTop) {
  82. syncScrollTop(targetTop);
  83. }
  84. }
  85. // We will retry since element may not sync height as it described
  86. scroll = (0, _raf.default)(() => {
  87. if (needCollectHeight) {
  88. collectHeight();
  89. }
  90. syncScroll(times - 1, newTargetAlign);
  91. }, 2);
  92. };
  93. syncScroll(5);
  94. }
  95. };
  96. }