Phase 1: Remove obsolete files and standardize all pages
- Standardize script loading on faq, privacy, returns, shipping-info pages - Archive 14 unused JS files (cart-functions, shopping, cart.js, enhanced versions, etc.) - Archive 2 unused CSS files (responsive-enhanced, responsive-fixes) - All pages now use consistent script loading order - Eliminated shopping.js dependency (not needed after standardization)
This commit is contained in:
210
website/public/assets/js/archive/lazy-load-optimized.js
Normal file
210
website/public/assets/js/archive/lazy-load-optimized.js
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Optimized Lazy Loading for Images
|
||||
* Improves page load time by deferring offscreen images
|
||||
* Uses Intersection Observer API for efficient monitoring
|
||||
*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// Configuration
|
||||
const CONFIG = {
|
||||
rootMargin: "50px", // Start loading 50px before entering viewport
|
||||
threshold: 0.01,
|
||||
loadingClass: "lazy-loading",
|
||||
loadedClass: "lazy-loaded",
|
||||
errorClass: "lazy-error",
|
||||
};
|
||||
|
||||
// Image cache to prevent duplicate loads
|
||||
const imageCache = new Set();
|
||||
|
||||
/**
|
||||
* Preload image and return promise
|
||||
*/
|
||||
function preloadImage(src) {
|
||||
if (imageCache.has(src)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
imageCache.add(src);
|
||||
resolve();
|
||||
};
|
||||
img.onerror = reject;
|
||||
img.src = src;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load image with fade-in effect
|
||||
*/
|
||||
async function loadImage(img) {
|
||||
const src = img.dataset.src;
|
||||
const srcset = img.dataset.srcset;
|
||||
|
||||
if (!src) return;
|
||||
|
||||
img.classList.add(CONFIG.loadingClass);
|
||||
|
||||
try {
|
||||
// Preload the image
|
||||
await preloadImage(src);
|
||||
|
||||
// Set the actual src
|
||||
img.src = src;
|
||||
if (srcset) {
|
||||
img.srcset = srcset;
|
||||
}
|
||||
|
||||
// Remove data attributes to free memory
|
||||
delete img.dataset.src;
|
||||
delete img.dataset.srcset;
|
||||
|
||||
// Add loaded class for fade-in animation
|
||||
img.classList.remove(CONFIG.loadingClass);
|
||||
img.classList.add(CONFIG.loadedClass);
|
||||
} catch (error) {
|
||||
console.error("Failed to load image:", src, error);
|
||||
img.classList.remove(CONFIG.loadingClass);
|
||||
img.classList.add(CONFIG.errorClass);
|
||||
|
||||
// Set fallback/placeholder if available
|
||||
if (img.dataset.fallback) {
|
||||
img.src = img.dataset.fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize lazy loading with Intersection Observer
|
||||
*/
|
||||
function initLazyLoad() {
|
||||
// Check for browser support
|
||||
if (!("IntersectionObserver" in window)) {
|
||||
// Fallback: load all images immediately
|
||||
console.warn("IntersectionObserver not supported, loading all images");
|
||||
const images = document.querySelectorAll("img[data-src]");
|
||||
images.forEach(loadImage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create observer
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
const img = entry.target;
|
||||
loadImage(img);
|
||||
observer.unobserve(img); // Stop observing once loaded
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
rootMargin: CONFIG.rootMargin,
|
||||
threshold: CONFIG.threshold,
|
||||
}
|
||||
);
|
||||
|
||||
// Observe all lazy images
|
||||
const lazyImages = document.querySelectorAll("img[data-src]");
|
||||
lazyImages.forEach((img) => observer.observe(img));
|
||||
|
||||
// Also observe images added dynamically
|
||||
const mutationObserver = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeName === "IMG" && node.dataset && node.dataset.src) {
|
||||
observer.observe(node);
|
||||
}
|
||||
// Check child images
|
||||
if (node.querySelectorAll) {
|
||||
const childImages = node.querySelectorAll("img[data-src]");
|
||||
childImages.forEach((img) => observer.observe(img));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
mutationObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
|
||||
// Store observers globally for cleanup
|
||||
window._lazyLoadObservers = { observer, mutationObserver };
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup observers (call on page unload if needed)
|
||||
*/
|
||||
function cleanup() {
|
||||
if (window._lazyLoadObservers) {
|
||||
const { observer, mutationObserver } = window._lazyLoadObservers;
|
||||
observer.disconnect();
|
||||
mutationObserver.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// Add CSS for loading states
|
||||
function injectStyles() {
|
||||
if (document.getElementById("lazy-load-styles")) return;
|
||||
|
||||
const style = document.createElement("style");
|
||||
style.id = "lazy-load-styles";
|
||||
style.textContent = `
|
||||
img[data-src] {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
img.lazy-loading {
|
||||
opacity: 0.5;
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: loading 1.5s infinite;
|
||||
}
|
||||
|
||||
img.lazy-loaded {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
img.lazy-error {
|
||||
opacity: 0.3;
|
||||
border: 2px dashed #ccc;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
/* Prevent layout shift */
|
||||
img[data-src] {
|
||||
min-height: 200px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
injectStyles();
|
||||
initLazyLoad();
|
||||
});
|
||||
} else {
|
||||
injectStyles();
|
||||
initLazyLoad();
|
||||
}
|
||||
|
||||
// Export for manual usage
|
||||
window.LazyLoad = {
|
||||
init: initLazyLoad,
|
||||
load: loadImage,
|
||||
cleanup: cleanup,
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user