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>