Skip to content

Vue Infinity is a modular toolkit designed to help developers build high-performance, memory-efficient, and media-rich applications with Vue. By leveraging smart data fetching and virtualized rendering, it ensures smooth user experiences even with large datasets.

License

Notifications You must be signed in to change notification settings

isaact/vue-infinity

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Decorative clouds

Vue-Infinity

Build lightning-fast Vue apps that only render what is on-screen

Vue-Infinity brings a radical efficiency boost to your UI by applying the same principle that powers 3D engines: if it’s not in visible, it doesn’t get rendered. This lets your app handle hundreds or thousands of elements without bloating memory, janking or killing batteries.

Whether you’re building infinite feeds, carousels, media galleries, or dashboardsβ€”Vue-Infinity keeps your app fast, smooth, and efficient.

πŸš€ Key Features

πŸ‘» Ghost Component

The Ghost component optimizes performance by conditionally rendering its slot content. When off-screen, the content is replaced by a dimensionally-identical placeholder, "unloading" heavy elements (like videos) while preserving layout.

  • Performance Boost: Unloads off-screen content to free up resources.
  • Layout Stability: Replaces hidden content with a correctly-sized placeholder.
  • Event-Driven: Emits events when its content becomes visible or hidden:
    • on-load: Fired when the component's content becomes visible and is rendered.
    • before-unload: Fired in the same tick that the component's content starts to become hidden.
    • on-unload: Fired in the next tick after the component's content has become hidden and replaced by the placeholder.

Example:

  <Ghost @on-load="handleLoad" @before-unload="handleBeforeUnload" @on-unload="handleUnload">
    <div style="height: 300px; background-color: lightblue;">
      This content will be replaced when not visible.
    </div>
  </Ghost>

πŸ‘» v-ghost Directive

The v-ghost directive offers a lightweight, flexible alternative to the Ghost component for optimizing performance. By applying v-ghost to any element, you can ensure its content is only rendered when it enters the viewport. When off-screen, the element's content is replaced by a placeholder, preserving layout integrity while freeing up system resources.

  • Minimalist Approach: A simple directive-based solution for lazy rendering.
  • Layout Preservation: Automatically measures the element and maintains its dimensions when off-screen.
  • Event-Driven Control: Provides onLoad, beforeUnload, and onUnload callbacks for fine-grained control over the element's lifecycle.

Basic Example (Video):

<template>
  <video controls muted playsinline v-ghost>
    <source src="your-video.mp4" type="video/mp4" />
  </video>
</template>

Advanced Example (All Options):

<template>
  <div v-ghost="{
    rootMargin: '100px',
    onLoad: handleLoad,
    beforeUnload: handleBeforeUnload,
    onUnload: handleUnload
  }">
    <!-- Heavy content goes here -->
  </div>
</template>

<script setup>
const handleLoad = () => {
  console.log('Content is now visible and rendered.');
};

const handleBeforeUnload = () => {
  console.log('Content is about to be hidden.');
};

const handleUnload = () => {
  console.log('Content is hidden and replaced by a placeholder.');
};
</script>

πŸͺ‚ InfiniteCarousel

A general-purpose virtual scroll component optimized for grid-like or carousel-based layouts.

  • Integrates directly with InfiniteList for managing data access
  • Customizable number of rows and columns
  • Configurable as a horizontal or vertical scroller
  • Supports custom templates for each item
  • Supports custom loading templates
  • Allows scrolling to any item with CSS-based scroll snapping
  • Supports dynamic item sizing by providing an onGetItemAspectRatio callback function that returns the aspect ratio of an item.

Example:

<template>
  <InfiniteCarousel
    :infinite-list="infiniteList"
    :height="'50vh'"
    :width="'100%'"
    :numColsToShow="3"
    :numRowsToShow="2"
  >
    <template #item="{ item, index }">
      <img :src="item.url" :alt="item.title" class="carousel-img"/>
    </template>
  </InfiniteCarousel>
</template>

<script setup>
import { useInfiniteList } from 'vue-infinity';

const infiniteList = useInfiniteList({
  fetchItems: (page) => fetchPage(page),
  itemsPerPage: 20,
  maxPagesToCache: 5
});
</script>

Example with Dynamic Item Sizing:

<template>
  <InfiniteCarousel
    :infinite-list="infiniteList"
    :height="'60vh'"
    :width="'100%'"
    :numColsToShow="4"
    :numRowsToShow="3"
    :onGetItemAspectRatio="getItemAspectRatio"
  >
    <template #item="{ item }">
      <img :src="item.url" :alt="item.title" class="carousel-img"/>
    </template>
  </InfiniteCarousel>
</template>

<script setup>
import { useInfiniteList } from 'vue-infinity';

const fetchItems = async (page) => {
  // Replace with your actual data fetching logic
  const response = await fetch(`/api/items?page=${page}`);
  return response.json();
};

const infiniteList = useInfiniteList({
  fetchItems,
  itemsPerPage: 30, // Adjust based on your data
  maxPagesToCache: 5
});

const getItemAspectRatio = (item) => {
  // Assuming item has width and height properties, or can be parsed from URL
  if (!item || !item.url) {
    return 1; // Default to square if aspect ratio cannot be determined
  }
  try {
    const urlParts = item.url.split('/');
    const width = parseInt(urlParts[urlParts.length - 2], 10);
    const height = parseInt(urlParts[urlParts.length - 1].split('?')[0], 10);
    return width / height;
  } catch (e) {
    console.error("Error parsing item aspect ratio:", e);
    return 1;
  }
};
</script>

πŸ”„ InfiniteList

Provides reactive, paginated access to large datasets with full type support.

  • Paginated data access
  • Caching with automatic unloading of older pages based on least-recently-used basis
  • Item access by index
  • Supports cancellation of in-flight network requests using AbortController

Example:

const { pages, getItem, fetchPage } = useInfiniteList({
  fetchItems: async (page, signal) => {
    const response = await fetch(`/api/items?page=${page}`, { signal });
    return response.json();
  },
  itemsPerPage: 50,
  maxPagesToCache: 5
});

πŸ”Ž AutoObserver

Enhances the native IntersectionObserver by automatically handling new elements and cleaning up removed ones.

  • Assign it to a target container and it automatically:
    • observes newly added elements
    • Stops observing removed elements
  • Allows filtering elements to observe using custom logic
  • Cleans up automatically on component unmount

Example:

const containerRef = ref<HTMLElement>();

const { disconnect } = useAutoObserver(
  containerRef,
  (entries) => {
    entries.forEach(entry => {
      console.log('Element visibility changed:', entry.isIntersecting);
    });
  },
  {
    rootMargin: '200px',
    threshold: 0.1,
    filter: el => el.classList.contains('observe-me')
  }
);

πŸ“¦ Installation

npm install vue-infinity

πŸ§ͺ Live Demo

Explore the live demo here: https://tewolde.co/vueInfinity/

πŸ§‘β€πŸ’» Run Playground App

To run the playground application locally:

npm run playground

Releases

v0.7.0 (2024-07-01)

  • v-ghost Directive: Introduced the new v-ghost directive to optimize performance by automatically unloading off-screen content.
  • Dynamic Item Sizing: The InfiniteCarousel now supports an onGetItemAspectRatio callback, enabling it to render items with variable heights.
  • Documentation Updates: Added instructions for the v-ghost directive and the dynamic sizing feature.

πŸ“„ License

Apache 2.0 License - https://opensource.org/licenses/Apache-2.0

About

Vue Infinity is a modular toolkit designed to help developers build high-performance, memory-efficient, and media-rich applications with Vue. By leveraging smart data fetching and virtualized rendering, it ensures smooth user experiences even with large datasets.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published