useStickyHeader.ts 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { useScroll } from '@vueuse/core'
  3. import type { CSSProperties, WatchSource } from 'vue'
  4. import { watch, ref } from 'vue'
  5. export const useStickyHeader = (
  6. dependencies: WatchSource[] = [],
  7. headerElement = ref<HTMLElement>(),
  8. ) => {
  9. const { y, directions } = useScroll(window.document, {
  10. eventListenerOptions: { passive: true },
  11. })
  12. const stickyStyles = ref<{ header?: CSSProperties; body?: CSSProperties }>({})
  13. watch(
  14. [y, ...dependencies],
  15. () => {
  16. if (!headerElement.value) {
  17. stickyStyles.value = {}
  18. return
  19. }
  20. const height = headerElement.value.clientHeight
  21. const show = y.value <= height || directions.top
  22. stickyStyles.value = {
  23. header: {
  24. left: '0',
  25. right: '0',
  26. top: '0',
  27. zIndex: 9,
  28. position: 'fixed',
  29. transform: `translateY(${show ? '0px' : '-100%'})`,
  30. transition: 'transform 0.3s ease-in-out',
  31. },
  32. body: {
  33. marginTop: `${height}px`,
  34. },
  35. } as const
  36. },
  37. { flush: 'post' },
  38. )
  39. return {
  40. stickyStyles,
  41. headerElement,
  42. }
  43. }