Giter VIP home page Giter VIP logo

metonym / svelte-intersection-observer Goto Github PK

View Code? Open in Web Editor NEW
310.0 4.0 7.0 1.17 MB

Detect if an element is in the viewport using the Intersection Observer API

Home Page: https://metonym.github.io/svelte-intersection-observer/

License: MIT License

JavaScript 1.12% Svelte 54.39% HTML 2.38% TypeScript 42.10%
intersection-observer viewport lazy-loading conditional svelte svelte-component typescript-definitions intersection-event

svelte-intersection-observer's Introduction

svelte-intersection-observer

NPM

Detect if an element is in the viewport using the Intersection Observer API.

Try it in the Svelte REPL.

Installation

# npm
npm i -D svelte-intersection-observer

# pnpm
pnpm i -D svelte-intersection-observer

# Bun
bun i -D svelte-intersection-observer

# Yarn
yarn add -D svelte-intersection-observer

Usage

Basic

Use the bind:this directive to pass an element reference to the IntersectionObserver component.

Then, simply bind to the reactive intersecting prop to determine if the element intersects the viewport.

<script>
  import IntersectionObserver from "svelte-intersection-observer";

  let element;
  let intersecting;
</script>

<header class:intersecting>
  {intersecting ? "Element is in view" : "Element is not in view"}
</header>

<IntersectionObserver {element} bind:intersecting>
  <div bind:this={element}>Hello world</div>
</IntersectionObserver>

Once

Set once to true for the intersection event to occur only once. The element will be unobserved after the first intersection event occurs.

<script>
  import IntersectionObserver from "svelte-intersection-observer";

  let elementOnce;
  let intersectOnce;
</script>

<header class:intersecting={intersectOnce}>
  {intersectOnce ? "Element is in view" : "Element is not in view"}
</header>

<IntersectionObserver
  once
  element={elementOnce}
  bind:intersecting={intersectOnce}
>
  <div bind:this={elementOnce}>Hello world</div>
</IntersectionObserver>

let:intersecting

An alternative to binding to the intersecting prop is to use the let: directive.

In the following example, the "Hello world" element will fade in when its containing element intersects the viewport.

<script>
  import IntersectionObserver from "svelte-intersection-observer";
  import { fade } from "svelte/transition";

  let node;
</script>

<header />

<IntersectionObserver element={node} let:intersecting>
  <div bind:this={node}>
    {#if intersecting}
      <div transition:fade={{ delay: 200 }}>Hello world</div>
    {/if}
  </div>
</IntersectionObserver>

on:observe event

The observe event is dispatched when the element is first observed and also whenever an intersection event occurs.

<IntersectionObserver
  {element}
  on:observe={(e) => {
    console.log(e.detail); // IntersectionObserverEntry
    console.log(e.detail.isIntersecting); // true | false
  }}
>
  <div bind:this={element}>Hello world</div>
</IntersectionObserver>

on:intersect event

As an alternative to binding the intersecting prop, you can listen to the intersect event that is dispatched if the observed element is intersecting the viewport.

Note: Compared to on:observe, on:intersect is dispatched only when the element is intersecting the viewport. In other words, e.detail.isIntersecting will only be true.

<IntersectionObserver
  {element}
  on:intersect={(e) => {
    console.log(e.detail); // IntersectionObserverEntry
    console.log(e.detail.isIntersecting); // true
  }}
>
  <div bind:this={element}>Hello world</div>
</IntersectionObserver>

API

Props

Name Description Type Default value
element Observed element HTMLElement null
once Unobserve the element after the first intersection event boolean false
intersecting true if the observed element is intersecting the viewport boolean false
root Containing element null or HTMLElement null
rootMargin Margin offset of the containing element string "0px"
threshold Percentage of element visibile to trigger an event number between 0 and 1, or an array of numbers between 0 and 1 0
entry Observed element metadata IntersectionObserverEntry null
observer IntersectionObserver instance IntersectionObserver null

Dispatched events

  • on:observe: fired when the element is first observed or whenever an intersection change occurs
  • on:intersect: fired when the element is intersecting the viewport

The e.detail dispatched by the observe and intersect events is an IntersectionObserverEntry interface.

Note that all properties in IntersectionObserverEntry are read-only.

IntersectionObserverEntry
interface IntersectionObserverEntry {
  target: HTMLElement;
  time: number;
  isIntersecting: boolean;
  isVisible: boolean;
  intersectionRatio: number;
  intersectionRect: {
    bottom: number;
    height: number;
    left: number;
    right: number;
    top: number;
    width: number;
    x: number;
    y: number;
  };
  rootBounds: {
    bottom: number;
    height: number;
    left: number;
    right: number;
    top: number;
    width: number;
    x: number;
    y: number;
  };
  boundingClientRect: {
    bottom: number;
    height: number;
    left: number;
    right: number;
    top: number;
    width: number;
    x: number;
    y: number;
  };
}

Changelog

Changelog

License

MIT

svelte-intersection-observer's People

Contributors

dependabot[bot] avatar dysfunc avatar harshmandan avatar kevinkace avatar metonym avatar nosovk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

svelte-intersection-observer's Issues

Installing a newer version?

Hi there.

I'm seeking to use your module with Svelte 3.49 (and Meteor, but I don't think that matters for this question). I can run npm install --save github:metonym/svelte-intersection-observer#master to install the code, but that doesn't run the build command. I've Googled without success so far. Would you willing and able to tell me how I can successfully install master in my project?

Thanks!

How to use it in jest?

Is there a way to pass it in jest ?

*.svelte

<IntersectionObserver {element} on:intersect={...}>
   <div bind:this={element}/>
</IntersectionObserver>

*.spec.js

import { render } from '@testing-library/svelte';

...

-- rendering test spec ---

But I got this message,
TypeError: IntersectionObserver is not a constructor

Is there a way to mock it?

Jitter

Jitter is caused when using multiple intersection observers, it works fine with one observer.
Any idea why this is happening?

what is the recommended approach to use multiple observers?

Component only works in one instance

I am using the svelte-intersaction-observer component in both my Cards component and my Article component all put inside my Home page. For some reason, I cannot use the intersection observer with both the Cards and the Article components without Article not working at all. It seems that I can only use the component once to get it to work.

Is there a way where I can copy or de-reference the InterfaceObserver component to have it work in multiple instances?

Reference Images:
image
image

Threshold value having no effect (SvelteKit)

<IntersectionObserver once element={node} let:intersecting threshold={0.1}>
		<div bind:this={node}>
			{#if intersecting}
				<img
					on:load={imageIsLoaded}
					src={image}
					alt={name}
				/>
			{/if}
		</div>
	</IntersectionObserver>

Regardless of the low threshold, the images only load when 100% intersected with the viewport. Is this a known issue, or am I doing something wrong?

IntersectionObserver inside Svelte #each block causes infinite loop

Not sure if this is an expected limitation or a bug, or perhaps specific to my project, but I get an infinite loop that locks up the app when I place <IntersectionObserver> into an #each block:

<script>
  import IntersectionObserver from 'svelte-intersection-observer';
  import Some from '$components/some.svelte';

  const sections = [
    {
      id: 'some',
      node: undefined,
      intersecting: undefined,
      component: Some,
    },
  ];
</script>

{#each sections as {id, node, intersecting, component}}
  <IntersectionObserver element={node} bind:intersecting>
    <section 
      id={id} 
      class:intersecting={intersecting} 
      bind:this={node}
    >
      <svelte:component this={component} />
    </section>
  </IntersectionObserver>
{/each}

Related: #63

Warning with `vite-plugin-svelte`

Hi when i use this package i get this warning

9:01:14 PM [vite-plugin-svelte] WARNING: The following packages have a svelte field in their package.json but no exports condition for svelte.

svelte-intersection-observer@0.10.1

Please see https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#missing-exports-condition for details.

Does this work with Sapper?

I'm not entirely sure why this wouldn't be working with Sapper, but it seems that when I comment out the IntersectionObserver component from code that works with normal Svelte, Sapper builds the site fine. I have no logs or errors coming from Sapper or Svelte. The only thing I know is that commenting out the component allows Sapper to render the site.

scrollIntoView with animate on scroll

My question is essentially how do we scroll to a specific element that have a transition effect?

So scroll into view scrolls to a specific element based on it's current position.
But what if that element is conditionally rendered with an animation?
Then the element is not visible in the DOM at the moment when the user wants to scroll to that element in the DOM.

I am using svelte-intersection-observer, not sure how to resolve this.

import IntersectionObserver from 'svelte-intersection-observer';
let infoNode: HTMLElement, featureNode: HTMLElement, faqNode: HTMLElement, priceNode: HTMLElement;


<div class="flex flex-col mt-32 gap-60">
  <div id="features">
    <IntersectionObserver once element={infoNode} let:intersecting>
      <div bind:this={infoNode}>
        {#if intersecting}
          <section
            in:fly={{ duration: 700, x: -150, opacity: 0.1, easing: cubicIn }}
            class="flex items-center justify-center"
          >
            <Info />
          </section>
        {/if}
      </div>
    </IntersectionObserver>
  </div>

  <IntersectionObserver once element={featureNode} let:intersecting>
    <div bind:this={featureNode}>
      {#if intersecting}
        <section
          in:fly={{ duration: 700, x: 150, opacity: 0.1, easing: cubicIn }}
          class="relative flex items-center justify-center"
        >
          <Features />
        </section>
      {/if}
    </div>
  </IntersectionObserver>

  <div id="pricing">
    <IntersectionObserver once element={priceNode} let:intersecting>
      <div bind:this={priceNode}>
        {#if intersecting}
          <section
            in:fly={{ duration: 700, x: 150, opacity: 0.1, easing: cubicIn }}
            class="relative flex items-center justify-center"
          >
            <Pricing />
          </section>
        {/if}
      </div>
    </IntersectionObserver>
  </div>

  <div id="faq">
    <IntersectionObserver once element={faqNode} let:intersecting>
      <div bind:this={faqNode}>
        {#if intersecting}
          <section
            in:fly={{ duration: 700, y: 150, opacity: 0.1, easing: cubicIn }}
            class="relative mb-56"
          >
            <Faq />
          </section>
        {/if}
      </div>
    </IntersectionObserver>
  </div>
</div>

Are there any workarounds to this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.