AnchoredSection.vue 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. <template>
  2. <div ref="section" v-scroll="onScroll" class="section">
  3. <div :id="id" class="anchor" />
  4. <slot />
  5. </div>
  6. </template>
  7. <script setup lang="ts">
  8. import type { Ref } from 'vue'
  9. import { useLayoutStore } from '~/stores/layoutStore'
  10. const layoutStore = useLayoutStore()
  11. const props = defineProps({
  12. id: {
  13. type: String,
  14. required: true,
  15. },
  16. })
  17. if (!props.id) {
  18. throw new Error("Anchor's id is missing")
  19. }
  20. const section: Ref<HTMLElement | null> = ref(null)
  21. layoutStore.setIsAnchoredSectionOnScreen(props.id, false)
  22. const top: Ref<number | null> = ref(null)
  23. const bottom: Ref<number | null> = ref(null)
  24. // @ts-ignore
  25. const onScroll = (scroll) => {
  26. top.value = section.value!.offsetTop
  27. bottom.value = section.value!.offsetTop + section.value!.offsetHeight
  28. if (top.value === null || bottom.value === null) {
  29. return
  30. }
  31. const screenVerticalCenter =
  32. scroll.target.documentElement.scrollTop + window.innerHeight / 2
  33. const active =
  34. screenVerticalCenter > top.value && screenVerticalCenter < bottom.value
  35. if (active !== layoutStore.isAnchoredSectionOnScreen[props.id]) {
  36. layoutStore.setIsAnchoredSectionOnScreen(props.id, active)
  37. }
  38. }
  39. </script>
  40. <style scoped lang="scss">
  41. .section {
  42. //position: relative;
  43. }
  44. .anchor {
  45. position: relative;
  46. top: -54px;
  47. }
  48. </style>