CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue-lazyload

Vue.js plugin for lazy-loading images and components with directives, components, and programmatic APIs

Pending
Overview
Eval results
Files

components.mddocs/

Lazy Components

Vue components for lazy loading content and images with full Vue 3 composition API support.

Capabilities

lazy-component

A wrapper component that lazily renders its content when it becomes visible in the viewport.

/**
 * Lazy component that renders content only when visible
 */
interface LazyComponentProps {
  /** HTML tag to render as wrapper (default: 'div') */
  tag?: string;
}

/**
 * Events emitted by lazy-component
 */
interface LazyComponentEvents {
  /** Emitted when component becomes visible and content is shown */
  show: (visible: boolean) => void;
}

/**
 * Slots available in lazy-component
 */
interface LazyComponentSlots {
  /** Default slot content that will be lazily rendered */
  default: () => VNode[];
}

Usage Examples:

<template>
  <!-- Basic lazy component -->
  <lazy-component @show="onComponentShow">
    <img src="/heavy-image.jpg" alt="Heavy image">
    <p>This content loads when visible</p>
  </lazy-component>
  
  <!-- Custom wrapper tag -->
  <lazy-component tag="section" @show="onSectionShow">
    <h2>Lazy Section</h2>
    <video src="/large-video.mp4" controls></video>
  </lazy-component>
  
  <!-- In a list -->
  <div class="image-gallery">
    <lazy-component 
      v-for="(item, index) in galleryItems" 
      :key="item.id"
      @show="() => onItemShow(index)"
    >
      <img :src="item.imageUrl" :alt="item.title">
      <h3>{{ item.title }}</h3>
    </lazy-component>
  </div>
</template>

<script setup>
import { ref } from "vue";

const galleryItems = ref([
  { id: 1, imageUrl: "/gallery1.jpg", title: "Image 1" },
  { id: 2, imageUrl: "/gallery2.jpg", title: "Image 2" },
  { id: 3, imageUrl: "/gallery3.jpg", title: "Image 3" },
]);

const onComponentShow = (visible) => {
  console.log("Component is now visible:", visible);
};

const onSectionShow = (visible) => {
  console.log("Section became visible:", visible);
};

const onItemShow = (index) => {
  console.log(`Gallery item ${index} is now visible`);
};
</script>

lazy-image

A specialized component for lazy loading images with built-in state management and error handling.

/**
 * Lazy image component with built-in loading states
 */
interface LazyImageProps {
  /** Image source URL or configuration object */
  src: string | VueLazyloadImageOptions;
  /** HTML tag to render (default: 'img') */
  tag?: string;
}

/**
 * Image options for lazy-image component
 */
interface VueLazyloadImageOptions {
  /** Image source URL */
  src: string;
  /** Error fallback image URL */
  error?: string;
  /** Loading placeholder image URL */
  loading?: string;
  /** Maximum loading attempts */
  attempt?: number;
}

/**
 * Slots available in lazy-image component
 */
interface LazyImageSlots {
  /** Optional slot content rendered alongside image */
  default?: () => VNode[];
}

Usage Examples:

<template>
  <!-- Basic lazy image -->
  <lazy-image src="/photo.jpg" />
  
  <!-- Image with configuration -->
  <lazy-image :src="{
    src: '/high-res-photo.jpg',
    loading: '/loading-placeholder.png',
    error: '/error-fallback.png',
    attempt: 3
  }" />
  
  <!-- Custom wrapper tag -->
  <lazy-image 
    tag="figure" 
    :src="imageConfig"
  >
    <figcaption>Image caption content</figcaption>
  </lazy-image>
  
  <!-- Dynamic image source -->
  <lazy-image 
    :src="computedImageSrc"
    @load="onImageLoaded"
    @error="onImageError"
  />
</template>

<script setup>
import { computed, ref } from "vue";

const imageConfig = ref({
  src: "/portrait.jpg",
  loading: "/skeleton-loader.svg",
  error: "/broken-image.svg",
  attempt: 5,
});

const imageQuality = ref("medium");
const imageName = ref("landscape");

const computedImageSrc = computed(() => ({
  src: `/images/${imageName.value}-${imageQuality.value}.jpg`,
  loading: "/placeholders/image-loading.svg",
  error: "/placeholders/image-error.svg",
}));

const onImageLoaded = () => {
  console.log("Lazy image successfully loaded");
};

const onImageError = () => {
  console.error("Failed to load lazy image");
};
</script>

Component Integration Patterns

Advanced usage patterns for integrating lazy components with other Vue features.

With Vue Router:

<template>
  <router-view v-slot="{ Component }">
    <lazy-component @show="onRouteComponentShow">
      <component :is="Component" />
    </lazy-component>
  </router-view>
</template>

<script setup>
import { useRoute } from "vue-router";

const route = useRoute();

const onRouteComponentShow = () => {
  console.log("Route component visible:", route.path);
};
</script>

With Suspense:

<template>
  <Suspense>
    <template #default>
      <lazy-component @show="onAsyncComponentShow">
        <AsyncComponent />
      </lazy-component>
    </template>
    <template #fallback>
      <div class="loading-placeholder">Loading async component...</div>
    </template>
  </Suspense>
</template>

<script setup>
import { defineAsyncComponent } from "vue";

const AsyncComponent = defineAsyncComponent(() => import("./HeavyComponent.vue"));

const onAsyncComponentShow = () => {
  console.log("Async component is now visible");
};
</script>

With Teleport:

<template>
  <lazy-component @show="onModalContentShow">
    <Teleport to="#modal-container">
      <div class="modal-content">
        <lazy-image :src="modalImageSrc" />
      </div>
    </Teleport>
  </lazy-component>
</template>

<script setup>
const modalImageSrc = ref("/modal-background.jpg");

const onModalContentShow = () => {
  console.log("Modal content is visible");
};
</script>

Performance Optimization

Optimizing lazy component performance for large lists and complex layouts.

Virtual Scrolling Integration:

<template>
  <div class="virtual-list" ref="scrollContainer">
    <lazy-component 
      v-for="item in visibleItems" 
      :key="item.id"
      @show="() => trackItemView(item.id)"
    >
      <ItemComponent :item="item" />
    </lazy-component>
  </div>
</template>

<script setup>
import { ref, computed } from "vue";

const scrollContainer = ref();
const allItems = ref([/* large array of items */]);

// Only render items in viewport + buffer
const visibleItems = computed(() => {
  // Implementation for virtual scrolling logic
  return allItems.value.slice(startIndex.value, endIndex.value);
});

const trackItemView = (itemId) => {
  // Analytics tracking when item becomes visible
  console.log("Item viewed:", itemId);
};
</script>

Intersection Observer Configuration:

<template>
  <lazy-component 
    @show="onHighPriorityShow"
    data-lazy-priority="high"
  >
    <CriticalContent />
  </lazy-component>
  
  <lazy-component 
    @show="onLowPriorityShow"
    data-lazy-priority="low"
  >
    <OptionalContent />
  </lazy-component>
</template>

<script setup>
// Components automatically inherit observer settings from plugin config
// Can be customized via global configuration during plugin installation

const onHighPriorityShow = () => {
  // Handle high priority content visibility
};

const onLowPriorityShow = () => {
  // Handle low priority content visibility
};
</script>

Component State Management

Managing component states and lifecycle hooks.

<template>
  <lazy-component @show="handleComponentShow">
    <div class="content-wrapper">
      <lazy-image 
        :src="imageSource"
        @loading="onImageLoading"
        @loaded="onImageLoaded"
        @error="onImageError"
      />
      <div class="content-text">
        {{ contentText }}
      </div>
    </div>
  </lazy-component>
</template>

<script setup>
import { ref, nextTick } from "vue";

const imageSource = ref("/initial-image.jpg");
const contentText = ref("Initial content");
const isComponentVisible = ref(false);

const handleComponentShow = async (visible) => {
  isComponentVisible.value = visible;
  
  if (visible) {
    // Load additional resources when component becomes visible
    await loadAdditionalResources();
  }
};

const onImageLoading = () => {
  console.log("Image started loading");
};

const onImageLoaded = () => {
  console.log("Image finished loading");
  // Trigger any post-load animations or updates
  nextTick(() => {
    // DOM updates after image load
  });
};

const onImageError = () => {
  console.error("Image failed to load");
  // Fallback behavior
  imageSource.value = "/fallback-image.jpg";
};

const loadAdditionalResources = async () => {
  // Fetch additional data when component is visible
  const response = await fetch("/api/additional-content");
  const data = await response.json();
  contentText.value = data.text;
};
</script>

Install with Tessl CLI

npx tessl i tessl/npm-vue-lazyload

docs

components.md

directives.md

index.md

plugin-installation.md

programmatic-api.md

tile.json