AnchoredSection.vue 1.2 KB

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