useScrollTo.ts 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { shallowRef, unref } from 'vue';
  2. interface UseScrollToOptions {
  3. el: any;
  4. to: number;
  5. duration?: number;
  6. callback?: () => any;
  7. }
  8. function easeInOutQuad(t: number, b: number, c: number, d: number) {
  9. t /= d / 2;
  10. if (t < 1) {
  11. return (c / 2) * t * t + b;
  12. }
  13. t--;
  14. return (-c / 2) * (t * (t - 2) - 1) + b;
  15. }
  16. function move(el: HTMLElement, amount: number) {
  17. el.scrollTop = amount;
  18. }
  19. const position = (el: HTMLElement) => {
  20. return el.scrollTop;
  21. };
  22. function useScrollTo({ el, to, duration = 500, callback }: UseScrollToOptions) {
  23. const isActiveRef = shallowRef(false);
  24. const start = position(el);
  25. const change = to - start;
  26. const increment = 20;
  27. let currentTime = 0;
  28. const animateScroll = function () {
  29. if (!unref(isActiveRef)) {
  30. return;
  31. }
  32. currentTime += increment;
  33. const val = easeInOutQuad(currentTime, start, change, duration);
  34. move(el, val);
  35. if (currentTime < duration && unref(isActiveRef)) {
  36. requestAnimationFrame(animateScroll);
  37. } else {
  38. if (callback && typeof callback === 'function') {
  39. callback();
  40. }
  41. }
  42. };
  43. const run = () => {
  44. isActiveRef.value = true;
  45. animateScroll();
  46. };
  47. const stop = () => {
  48. isActiveRef.value = false;
  49. };
  50. return { start: run, stop };
  51. }
  52. export { useScrollTo, type UseScrollToOptions };