use-scroll-lock.ts 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import { getScrollbarWidth, needsScrollbar } from '@vben-core/shared/utils';
  2. import {
  3. useScrollLock as _useScrollLock,
  4. tryOnBeforeUnmount,
  5. tryOnMounted,
  6. } from '@vueuse/core';
  7. export const SCROLL_FIXED_CLASS = `_scroll__fixed_`;
  8. export function useScrollLock() {
  9. const isLocked = _useScrollLock(document.body);
  10. const scrollbarWidth = getScrollbarWidth();
  11. tryOnMounted(() => {
  12. if (!needsScrollbar()) {
  13. return;
  14. }
  15. document.body.style.paddingRight = `${scrollbarWidth}px`;
  16. const layoutFixedNodes = document.querySelectorAll<HTMLElement>(
  17. `.${SCROLL_FIXED_CLASS}`,
  18. );
  19. const nodes = [...layoutFixedNodes];
  20. if (nodes.length > 0) {
  21. nodes.forEach((node) => {
  22. node.dataset.transition = node.style.transition;
  23. node.style.transition = 'none';
  24. node.style.paddingRight = `${scrollbarWidth}px`;
  25. });
  26. }
  27. isLocked.value = true;
  28. });
  29. tryOnBeforeUnmount(() => {
  30. if (!needsScrollbar()) {
  31. return;
  32. }
  33. isLocked.value = false;
  34. const layoutFixedNodes = document.querySelectorAll<HTMLElement>(
  35. `.${SCROLL_FIXED_CLASS}`,
  36. );
  37. const nodes = [...layoutFixedNodes];
  38. if (nodes.length > 0) {
  39. nodes.forEach((node) => {
  40. node.style.paddingRight = '';
  41. requestAnimationFrame(() => {
  42. node.style.transition = node.dataset.transition || '';
  43. });
  44. });
  45. }
  46. document.body.style.paddingRight = '';
  47. });
  48. }