Skip to content

Commit

Permalink
fix: IntersectionObserverShared only fire intersected event when actu…
Browse files Browse the repository at this point in the history
…ally intersecting
  • Loading branch information
jacob-8 committed Aug 14, 2024
1 parent 6959d2a commit 7c8d39e
Showing 1 changed file with 51 additions and 50 deletions.
101 changes: 51 additions & 50 deletions src/lib/functions/IntersectionObserverShared.svelte
Original file line number Diff line number Diff line change
@@ -1,114 +1,115 @@
<script lang="ts" context="module">
let observer: IntersectionObserver;
let observer: IntersectionObserver
// As each element registers with the observer, map Elements to Callbacks so when an element's intersection changes its callback is invoked
const mapping = new Map();
const mapping = new Map()
function add(element: HTMLElement, callback: (isIntersecting: boolean) => void) {
mapping.set(element, callback);
observer.observe(element);
mapping.set(element, callback)
observer.observe(element)
}
function remove(element: HTMLElement) {
const deleted = mapping.delete(element);
deleted && observer.unobserve(element);
const deleted = mapping.delete(element)
deleted && observer.unobserve(element)
}
</script>

<script lang="ts">
import { onMount, onDestroy, createEventDispatcher } from "svelte";
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
/**
* Set to `true` to unobserve the element after it intersects the viewport.
*/
export let once = false;
export let intervalMs: number = undefined;
export let top = 0;
export let bottom = 0;
export let left = 0;
export let right = 0;
export let once = false
export let intervalMs: number = undefined
export let top = 0
export let bottom = 0
export let left = 0
export let right = 0
/**
* Percentage of element visibility to trigger an event.
* Value must be between 0 and 1.
*/
export let threshold = 0;
export let threshold = 0
let intersecting = false;
let container: HTMLDivElement;
let childElement: HTMLElement;
let interval;
let intersecting = false
let container: HTMLDivElement
let childElement: HTMLElement
let interval
const dispatch = createEventDispatcher<{ intersected: null, hidden: null }>()
onMount(() => {
childElement = container.firstElementChild as HTMLElement;
childElement = container.firstElementChild as HTMLElement
if (!childElement) {
return console.error("IntersectionObserver: No child element found");
return console.error('IntersectionObserver: No child element found')
}
if (typeof IntersectionObserver !== "undefined") {
if (typeof IntersectionObserver !== 'undefined') {
if (!observer) {
let isIframe = window !== window.parent;
let root = isIframe ? window.document : null; // Use the iframe's document as root if in an iframe
const isIframe = window !== window.parent
const root = isIframe ? window.document : null // Use the iframe's document as root if in an iframe
const rootMargin = `${top}px ${right}px ${bottom}px ${left}px`;
const rootMargin = `${top}px ${right}px ${bottom}px ${left}px`
observer = new IntersectionObserver(
(entries) => {
for (var entry of entries) {
const callback = mapping.get(entry.target);
callback && callback(entry.isIntersecting);
for (const entry of entries) {
const callback = mapping.get(entry.target)
callback && callback(entry.isIntersecting)
}
},
{
root,
rootMargin,
threshold,
},
);
)
}
const fired_when_interesecting_changes = (isIntersecting: boolean) => {
if (once && isIntersecting) remove(childElement);
dispatch('intersected');
intersecting = isIntersecting;
};
add(childElement, fired_when_interesecting_changes);
if (once && isIntersecting) remove(childElement)
if (isIntersecting) dispatch('intersected')
intersecting = isIntersecting
}
add(childElement, fired_when_interesecting_changes)
return () => remove(childElement);
return () => remove(childElement)
}
function handler() {
const bcr = childElement.getBoundingClientRect();
intersecting =
bcr.bottom + bottom > 0 &&
bcr.right + right > 0 &&
bcr.top - top < window.innerHeight &&
bcr.left - left < window.innerWidth;
const bcr = childElement.getBoundingClientRect()
intersecting
= bcr.bottom + bottom > 0
&& bcr.right + right > 0
&& bcr.top - top < window.innerHeight
&& bcr.left - left < window.innerWidth
if (intersecting && once) {
window.removeEventListener("scroll", handler);
window.removeEventListener('scroll', handler)
}
}
window.addEventListener("scroll", handler);
return () => window.removeEventListener("scroll", handler);
});
window.addEventListener('scroll', handler)
return () => window.removeEventListener('scroll', handler)
})
const dispatch = createEventDispatcher<{ intersected: null; hidden: null }>();
$: if (intersecting === true) {
if (intervalMs) {
interval = setInterval(() => {
if (intersecting === true) {
dispatch("intersected");
dispatch('intersected')
}
}, intervalMs);
}, intervalMs)
}
} else {
dispatch("hidden");
dispatch('hidden')
}
onDestroy(() => {
clearInterval(interval);
});
clearInterval(interval)
})
</script>

<div style="display: contents" bind:this={container}>
Expand Down

0 comments on commit 7c8d39e

Please sign in to comment.