Vue.js plugin for lazy-loading images and components with directives, components, and programmatic APIs
—
Direct access to the lazy loading handler for manual control, event handling, and performance monitoring.
Access the main lazy loading handler instance through Vue's global properties or injection system.
/**
* Main lazy loading handler interface
*/
interface VueLazyloadHandler {
/** Register event listener for lazy loading events */
$on(event: LazyEventType, callback: VueLazyloadListenEvent): void;
/** Register one-time event listener */
$once(event: LazyEventType, callback: VueLazyloadListenEvent): void;
/** Remove event listener */
$off(event: LazyEventType, callback?: VueLazyloadListenEvent): void;
/** Manually trigger lazy load check */
lazyLoadHandler(): void;
/** Get performance metrics for all listeners */
performance(): VueReactiveListener[];
/** Manually add element for lazy loading */
add(el: HTMLElement, binding: DirectiveBinding, vnode: VNode): void;
/** Update element configuration */
update(el: HTMLElement, binding: DirectiveBinding, vnode?: VNode): void;
/** Remove element from lazy loading */
remove(el: HTMLElement): void;
/** Set loading mode (event or observer) */
setMode(mode: "event" | "observer"): void;
/** Add lazy component to queue */
addLazyBox(vm: LazyComponentInstance): void;
/** Remove lazy component from queue */
removeComponent(vm: LazyComponentInstance): void;
}
/**
* Event types for lazy loading
*/
type LazyEventType = "loading" | "loaded" | "error";
/**
* Event callback interface
*/
interface VueLazyloadListenEvent {
(listener: VueReactiveListener, cache: boolean): void;
}
/**
* Reactive listener representing a lazy-loaded element
*/
interface VueReactiveListener {
el: Element;
src: string;
error: string;
loading: string;
bindType: string;
attempt: number;
naturalHeight: number;
naturalWidth: number;
options: VueLazyloadOptions;
rect: DOMRect;
$parent: Element;
elRenderer: Function;
performanceData: Performance;
}
/**
* Lazy component instance for programmatic control
*/
interface LazyComponentInstance {
el: HTMLElement;
rect: DOMRect;
checkInView(): boolean;
load(): void;
state: {
loaded: boolean;
error: boolean;
attempt: number;
};
}Usage Examples:
import { getCurrentInstance } from "vue";
// Access in composition API
const instance = getCurrentInstance();
const lazyload = instance?.appContext.config.globalProperties.$Lazyload;
// Register event listeners
lazyload?.$on("loaded", (listener, fromCache) => {
console.log("Image loaded:", listener.src);
console.log("From cache:", fromCache);
console.log("Natural dimensions:", listener.naturalWidth, "x", listener.naturalHeight);
});
lazyload?.$on("loading", (listener) => {
console.log("Loading started:", listener.src);
console.log("Attempt:", listener.attempt);
});
lazyload?.$on("error", (listener) => {
console.error("Loading failed:", listener.src);
console.log("Max attempts reached:", listener.attempt >= listener.options.attempt);
});
// Manual lazy load trigger
const triggerLazyLoad = () => {
lazyload?.lazyLoadHandler();
};
// Get performance data
const getPerformanceMetrics = () => {
const metrics = lazyload?.performance() || [];
return metrics.map(listener => ({
src: listener.src,
loadTime: listener.performanceData.loadEnd - listener.performanceData.loadStart,
totalTime: listener.performanceData.loadEnd - listener.performanceData.init,
}));
};Comprehensive event handling for monitoring lazy loading lifecycle.
/**
* Performance timing data for loaded images
*/
interface Performance {
/** Timestamp when listener was initialized */
init: number;
/** Timestamp when loading started */
loadStart: number;
/** Timestamp when loading completed */
loadEnd: number;
}
/**
* Event data passed to event listeners
*/
interface LazyEventData {
listener: VueReactiveListener;
fromCache: boolean;
}Usage Examples:
<script setup>
import { getCurrentInstance, onMounted, onUnmounted } from "vue";
const instance = getCurrentInstance();
const lazyload = instance?.appContext.config.globalProperties.$Lazyload;
// Event handlers
const handleImageLoaded = (listener, cache) => {
const loadTime = listener.performanceData.loadEnd - listener.performanceData.loadStart;
console.log(`Image ${listener.src} loaded in ${loadTime}ms (cached: ${cache})`);
// Track analytics
trackImageLoad({
src: listener.src,
loadTime,
fromCache: cache,
dimensions: {
width: listener.naturalWidth,
height: listener.naturalHeight
}
});
};
const handleImageError = (listener, cache) => {
console.error("Failed to load:", listener.src);
// Report error
reportImageError({
src: listener.src,
attempt: listener.attempt,
errorFallback: listener.error
});
};
const handleImageLoading = (listener, cache) => {
console.log("Starting to load:", listener.src);
// Show loading indicator
showLoadingIndicator(listener.el);
};
// Lifecycle management
onMounted(() => {
if (lazyload) {
lazyload.$on("loaded", handleImageLoaded);
lazyload.$on("error", handleImageError);
lazyload.$on("loading", handleImageLoading);
}
});
onUnmounted(() => {
if (lazyload) {
lazyload.$off("loaded", handleImageLoaded);
lazyload.$off("error", handleImageError);
lazyload.$off("loading", handleImageLoading);
}
});
// Utility functions
const trackImageLoad = (data) => {
// Send to analytics service
};
const reportImageError = (error) => {
// Send to error reporting service
};
const showLoadingIndicator = (element) => {
element.classList.add("loading");
};
</script>Programmatically add, update, and remove elements from lazy loading.
/**
* Manual element management methods
*/
interface ManualElementControl {
/** Add element to lazy loading queue */
add(el: HTMLElement, binding: DirectiveBinding, vnode: VNode): void;
/** Update element lazy loading configuration */
update(el: HTMLElement, binding: DirectiveBinding, vnode?: VNode): void;
/** Remove element from lazy loading */
remove(el: HTMLElement): void;
}
/**
* Directive binding simulation for manual control
*/
interface ManualDirectiveBinding {
value: string | VueLazyloadImageOptions;
arg?: string;
modifiers?: Record<string, boolean>;
instance?: ComponentPublicInstance;
}Usage Examples:
<script setup>
import { ref, onMounted, getCurrentInstance } from "vue";
const instance = getCurrentInstance();
const lazyload = instance?.appContext.config.globalProperties.$Lazyload;
const imageElement = ref<HTMLElement>();
const dynamicImages = ref<HTMLElement[]>([]);
// Manual element addition
const addImageToLazyLoad = (element: HTMLElement, imageUrl: string) => {
const binding = {
value: {
src: imageUrl,
loading: "/loading.gif",
error: "/error.png"
},
instance: instance?.proxy
};
lazyload?.add(element, binding as DirectiveBinding, {} as VNode);
};
// Update image source
const updateImageSource = (element: HTMLElement, newUrl: string) => {
const binding = {
value: newUrl,
instance: instance?.proxy
};
lazyload?.update(element, binding as DirectiveBinding);
};
// Remove from lazy loading
const removeFromLazyLoad = (element: HTMLElement) => {
lazyload?.remove(element);
};
// Dynamic image gallery management
const addImageToGallery = (imageUrl: string) => {
const img = document.createElement("img");
img.alt = "Dynamic image";
// Add to DOM
const gallery = document.getElementById("dynamic-gallery");
gallery?.appendChild(img);
// Add to lazy loading
addImageToLazyLoad(img, imageUrl);
// Track element
dynamicImages.value.push(img);
};
const clearGallery = () => {
dynamicImages.value.forEach(img => {
removeFromLazyLoad(img);
img.remove();
});
dynamicImages.value = [];
};
// Batch operations
const batchUpdateImages = (updates: Array<{element: HTMLElement, url: string}>) => {
updates.forEach(({element, url}) => {
updateImageSource(element, url);
});
// Trigger manual check after batch updates
lazyload?.lazyLoadHandler();
};
onMounted(() => {
// Example: Add initial images
const initialImages = [
"/gallery/image1.jpg",
"/gallery/image2.jpg",
"/gallery/image3.jpg"
];
initialImages.forEach(url => {
addImageToGallery(url);
});
});
</script>
<template>
<div>
<button @click="addImageToGallery('/new-image.jpg')">Add Image</button>
<button @click="clearGallery">Clear Gallery</button>
<div id="dynamic-gallery"></div>
</div>
</template>Monitor and analyze lazy loading performance across your application.
/**
* Performance monitoring interface
*/
interface PerformanceMonitoring {
/** Get detailed performance metrics for all listeners */
performance(): VueReactiveListener[];
/** Generate performance summary */
getPerformanceSummary(): PerformanceSummary;
}
/**
* Performance summary data
*/
interface PerformanceSummary {
totalImages: number;
loadedImages: number;
errorImages: number;
averageLoadTime: number;
cacheHitRate: number;
largestImage: {
src: string;
size: { width: number; height: number };
loadTime: number;
};
}Usage Examples:
// Performance monitoring utility
class LazyLoadMonitor {
private lazyload: VueLazyloadHandler;
private metrics: Map<string, PerformanceMetric> = new Map();
constructor(lazyloadHandler: VueLazyloadHandler) {
this.lazyload = lazyloadHandler;
this.setupEventListeners();
}
private setupEventListeners() {
this.lazyload.$on("loading", (listener) => {
this.metrics.set(listener.src, {
src: listener.src,
startTime: Date.now(),
attempt: listener.attempt,
});
});
this.lazyload.$on("loaded", (listener, fromCache) => {
const metric = this.metrics.get(listener.src);
if (metric) {
metric.endTime = Date.now();
metric.loadTime = metric.endTime - metric.startTime;
metric.fromCache = fromCache;
metric.dimensions = {
width: listener.naturalWidth,
height: listener.naturalHeight,
};
}
});
this.lazyload.$on("error", (listener) => {
const metric = this.metrics.get(listener.src);
if (metric) {
metric.error = true;
metric.endTime = Date.now();
}
});
}
getReport(): PerformanceReport {
const allMetrics = Array.from(this.metrics.values());
const successfulLoads = allMetrics.filter(m => !m.error && m.loadTime);
return {
totalRequests: allMetrics.length,
successfulLoads: successfulLoads.length,
errorCount: allMetrics.filter(m => m.error).length,
averageLoadTime: successfulLoads.reduce((sum, m) => sum + (m.loadTime || 0), 0) / successfulLoads.length,
cacheHitRate: successfulLoads.filter(m => m.fromCache).length / successfulLoads.length,
slowestImage: successfulLoads.reduce((slowest, current) =>
(current.loadTime || 0) > (slowest.loadTime || 0) ? current : slowest
),
largestImage: successfulLoads.reduce((largest, current) => {
const currentSize = (current.dimensions?.width || 0) * (current.dimensions?.height || 0);
const largestSize = (largest.dimensions?.width || 0) * (largest.dimensions?.height || 0);
return currentSize > largestSize ? current : largest;
}),
};
}
exportMetrics(): string {
return JSON.stringify(this.getReport(), null, 2);
}
}
interface PerformanceMetric {
src: string;
startTime: number;
endTime?: number;
loadTime?: number;
fromCache?: boolean;
attempt: number;
error?: boolean;
dimensions?: { width: number; height: number };
}
interface PerformanceReport {
totalRequests: number;
successfulLoads: number;
errorCount: number;
averageLoadTime: number;
cacheHitRate: number;
slowestImage: PerformanceMetric;
largestImage: PerformanceMetric;
}
// Usage
const monitor = new LazyLoadMonitor(lazyload);
// Get performance report
setTimeout(() => {
const report = monitor.getReport();
console.log("Lazy loading performance:", report);
// Export for analysis
const metrics = monitor.exportMetrics();
localStorage.setItem("lazyload-metrics", metrics);
}, 10000);Control lazy loading detection mode between event-based and IntersectionObserver-based approaches.
/**
* Mode management interface
*/
interface ModeManagement {
/** Set loading detection mode */
setMode(mode: "event" | "observer"): void;
/** Current active mode */
mode: string;
}Usage Examples:
// Dynamic mode switching based on performance
const optimizeLazyLoadMode = () => {
const isMobile = window.innerWidth < 768;
const hasIntersectionObserver = "IntersectionObserver" in window;
const isSlowConnection = navigator.connection?.effectiveType === "slow-2g";
if (hasIntersectionObserver && (isMobile || isSlowConnection)) {
// Use observer mode for better performance on mobile/slow connections
lazyload?.setMode("observer");
console.log("Switched to IntersectionObserver mode");
} else {
// Use event mode for desktop with fast connections
lazyload?.setMode("event");
console.log("Switched to event-based mode");
}
};
// Switch modes based on scroll performance
let scrollPerformance = 0;
const measureScrollPerformance = () => {
const start = performance.now();
const scrollHandler = () => {
const end = performance.now();
scrollPerformance = end - start;
// If scroll events are slow, switch to observer mode
if (scrollPerformance > 16 && lazyload?.mode === "event") {
lazyload.setMode("observer");
}
window.removeEventListener("scroll", scrollHandler);
};
window.addEventListener("scroll", scrollHandler, { once: true });
// Trigger a scroll event
window.scrollBy(0, 1);
};
// Initialize optimal mode
optimizeLazyLoadMode();
measureScrollPerformance();Install with Tessl CLI
npx tessl i tessl/npm-vue-lazyload