useScroll.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import { unref } from "vue";
  2. export const useScroll = () => {
  3. /**
  4. * Scrolls to a target element within a scroll container.
  5. * The function is agnostic to whether the container is a QScrollArea or a native DOM element.
  6. *
  7. * @param {Ref<Component|HTMLElement>} targetRef - Ref to the target component or DOM element.
  8. * @param {Ref<Component|HTMLElement>} containerRef - Ref to the container (QScrollArea or a scrollable DOM element like body).
  9. * @param {Object} options - Scroll options.
  10. * @param {number} options.offset - Offset from the top in pixels (default: 50).
  11. * @param {number} options.duration - Animation duration for QScrollArea (default: 150). Note: duration is not supported for native scrolling.
  12. * @returns {boolean} - Whether the scroll was successful.
  13. */
  14. const scrollToComponent = (targetRef, containerRef, options = {}) => {
  15. const { offset = 150, duration = 150 } = options;
  16. const targetInstance = unref(targetRef);
  17. const containerInstance = unref(containerRef);
  18. const targetElement = targetInstance?.$el ?? targetInstance;
  19. const containerElement = containerInstance?.$el ?? containerInstance;
  20. if (!targetElement || !containerElement) {
  21. console.warn("useScroll: Target or container element not found");
  22. return false;
  23. }
  24. try {
  25. let currentElement = targetElement;
  26. let offsetTop = 0;
  27. while (currentElement && currentElement !== containerElement) {
  28. offsetTop += currentElement.offsetTop;
  29. if (
  30. containerElement.contains(currentElement.offsetParent) ||
  31. containerElement === document.body
  32. ) {
  33. currentElement = currentElement.offsetParent;
  34. } else {
  35. currentElement = null;
  36. }
  37. }
  38. if (
  39. containerElement !== document.body &&
  40. !containerElement.contains(targetElement)
  41. ) {
  42. console.warn("useScroll: Target is not a child of the container");
  43. return false;
  44. }
  45. const targetPosition = Math.max(0, offsetTop - offset);
  46. if (typeof containerInstance.setScrollPosition === "function") {
  47. containerInstance.setScrollPosition(
  48. "vertical",
  49. targetPosition,
  50. duration,
  51. );
  52. } else {
  53. const scrollable =
  54. containerElement === document.body ? window : containerElement;
  55. scrollable.scrollTo({
  56. top: targetPosition,
  57. behavior: "smooth",
  58. });
  59. }
  60. return true;
  61. } catch (error) {
  62. console.error("useScroll: Error while scrolling", error);
  63. return false;
  64. }
  65. };
  66. return {
  67. scrollToComponent,
  68. };
  69. };