AnchoredSection.vue 1.2 KB

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