sticky.mjs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Utilities
  2. import { computed, onBeforeUnmount, onMounted, shallowRef, watch } from 'vue';
  3. import { convertToUnit } from "../../util/index.mjs"; // Types
  4. export function useSticky(_ref) {
  5. let {
  6. rootEl,
  7. isSticky,
  8. layoutItemStyles
  9. } = _ref;
  10. const isStuck = shallowRef(false);
  11. const stuckPosition = shallowRef(0);
  12. const stickyStyles = computed(() => {
  13. const side = typeof isStuck.value === 'boolean' ? 'top' : isStuck.value;
  14. return [isSticky.value ? {
  15. top: 'auto',
  16. bottom: 'auto',
  17. height: undefined
  18. } : undefined, isStuck.value ? {
  19. [side]: convertToUnit(stuckPosition.value)
  20. } : {
  21. top: layoutItemStyles.value.top
  22. }];
  23. });
  24. onMounted(() => {
  25. watch(isSticky, val => {
  26. if (val) {
  27. window.addEventListener('scroll', onScroll, {
  28. passive: true
  29. });
  30. } else {
  31. window.removeEventListener('scroll', onScroll);
  32. }
  33. }, {
  34. immediate: true
  35. });
  36. });
  37. onBeforeUnmount(() => {
  38. window.removeEventListener('scroll', onScroll);
  39. });
  40. let lastScrollTop = 0;
  41. function onScroll() {
  42. const direction = lastScrollTop > window.scrollY ? 'up' : 'down';
  43. const rect = rootEl.value.getBoundingClientRect();
  44. const layoutTop = parseFloat(layoutItemStyles.value.top ?? 0);
  45. const top = window.scrollY - Math.max(0, stuckPosition.value - layoutTop);
  46. const bottom = rect.height + Math.max(stuckPosition.value, layoutTop) - window.scrollY - window.innerHeight;
  47. const bodyScroll = parseFloat(getComputedStyle(rootEl.value).getPropertyValue('--v-body-scroll-y')) || 0;
  48. if (rect.height < window.innerHeight - layoutTop) {
  49. isStuck.value = 'top';
  50. stuckPosition.value = layoutTop;
  51. } else if (direction === 'up' && isStuck.value === 'bottom' || direction === 'down' && isStuck.value === 'top') {
  52. stuckPosition.value = window.scrollY + rect.top - bodyScroll;
  53. isStuck.value = true;
  54. } else if (direction === 'down' && bottom <= 0) {
  55. stuckPosition.value = 0;
  56. isStuck.value = 'bottom';
  57. } else if (direction === 'up' && top <= 0) {
  58. if (!bodyScroll) {
  59. stuckPosition.value = rect.top + top;
  60. isStuck.value = 'top';
  61. } else if (isStuck.value !== 'top') {
  62. stuckPosition.value = -top + bodyScroll + layoutTop;
  63. isStuck.value = 'top';
  64. }
  65. }
  66. lastScrollTop = window.scrollY;
  67. }
  68. return {
  69. isStuck,
  70. stickyStyles
  71. };
  72. }
  73. //# sourceMappingURL=sticky.mjs.map