AnchoredSection.vue 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  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. nextTick(() => {
  38. layoutStore.setIsAnchoredSectionOnScreen(
  39. props.id,
  40. active
  41. )
  42. })
  43. }
  44. }
  45. </script>
  46. <style scoped>
  47. </style>