useScrollTo.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { useEvent } from 'rc-util';
  2. import raf from "rc-util/es/raf";
  3. import isVisible from "rc-util/es/Dom/isVisible";
  4. import * as React from 'react';
  5. var SPEED_PTG = 1 / 3;
  6. export default function useScrollTo(ulRef, value) {
  7. // ========================= Scroll =========================
  8. var scrollingRef = React.useRef(false);
  9. var scrollRafRef = React.useRef(null);
  10. var scrollDistRef = React.useRef(null);
  11. var isScrolling = function isScrolling() {
  12. return scrollingRef.current;
  13. };
  14. var stopScroll = function stopScroll() {
  15. raf.cancel(scrollRafRef.current);
  16. scrollingRef.current = false;
  17. };
  18. var scrollRafTimesRef = React.useRef();
  19. var startScroll = function startScroll() {
  20. var ul = ulRef.current;
  21. scrollDistRef.current = null;
  22. scrollRafTimesRef.current = 0;
  23. if (ul) {
  24. var targetLi = ul.querySelector("[data-value=\"".concat(value, "\"]"));
  25. var firstLi = ul.querySelector("li");
  26. var doScroll = function doScroll() {
  27. stopScroll();
  28. scrollingRef.current = true;
  29. scrollRafTimesRef.current += 1;
  30. var currentTop = ul.scrollTop;
  31. var firstLiTop = firstLi.offsetTop;
  32. var targetLiTop = targetLi.offsetTop;
  33. var targetTop = targetLiTop - firstLiTop;
  34. // Wait for element exist. 5 frames is enough
  35. if (targetLiTop === 0 && targetLi !== firstLi || !isVisible(ul)) {
  36. if (scrollRafTimesRef.current <= 5) {
  37. scrollRafRef.current = raf(doScroll);
  38. }
  39. return;
  40. }
  41. var nextTop = currentTop + (targetTop - currentTop) * SPEED_PTG;
  42. var dist = Math.abs(targetTop - nextTop);
  43. // Break if dist get larger, which means user is scrolling
  44. if (scrollDistRef.current !== null && scrollDistRef.current < dist) {
  45. stopScroll();
  46. return;
  47. }
  48. scrollDistRef.current = dist;
  49. // Stop when dist is less than 1
  50. if (dist <= 1) {
  51. ul.scrollTop = targetTop;
  52. stopScroll();
  53. return;
  54. }
  55. // IE not support `scrollTo`
  56. ul.scrollTop = nextTop;
  57. scrollRafRef.current = raf(doScroll);
  58. };
  59. if (targetLi && firstLi) {
  60. doScroll();
  61. }
  62. }
  63. };
  64. // ======================== Trigger =========================
  65. var syncScroll = useEvent(startScroll);
  66. return [syncScroll, stopScroll, isScrolling];
  67. }