AnchoredSection.vue 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  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. onMounted(() => {
  27. top.value = section.value!.offsetTop
  28. bottom.value = section.value!.offsetTop + section.value!.offsetHeight
  29. })
  30. const onScroll = (e: any) => {
  31. if (top.value === null || bottom.value === null) {
  32. return
  33. }
  34. const screenVerticalCenter = document.documentElement.scrollTop + window.innerHeight / 2
  35. const active = screenVerticalCenter > top.value && screenVerticalCenter < bottom.value
  36. if (active !== layoutStore.isAnchoredSectionOnScreen[props.id]) {
  37. layoutStore.setIsAnchoredSectionOnScreen(
  38. props.id,
  39. active
  40. )
  41. }
  42. }
  43. </script>
  44. <style scoped>
  45. </style>