feat(carousel): enhance image loading strategy and improve product display in carousel
This commit is contained in:
@@ -2,10 +2,12 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
PLATFORM_ID,
|
||||
WritableSignal,
|
||||
computed,
|
||||
effect,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { isPlatformBrowser } from '@angular/common';
|
||||
@@ -20,11 +22,15 @@ export class MainCarouselComponent {
|
||||
private readonly platformId = inject(PLATFORM_ID);
|
||||
private readonly requestedIndex = signal(0);
|
||||
private readonly paused = signal(false);
|
||||
private readonly loadedIndexes = signal<ReadonlySet<number>>(new Set());
|
||||
private readonly settledIndexes = signal<ReadonlySet<number>>(new Set());
|
||||
private firstImageReadyEmitted = false;
|
||||
|
||||
readonly images = input.required<readonly string[]>();
|
||||
readonly imageAlts = input<readonly string[]>([]);
|
||||
readonly autoSlideInterval = input(5000);
|
||||
readonly ariaLabel = input('Imágenes destacadas');
|
||||
readonly firstImageReady = output<void>();
|
||||
|
||||
protected readonly activeIndex = computed(() => {
|
||||
const imageCount = this.images().length;
|
||||
@@ -32,8 +38,27 @@ export class MainCarouselComponent {
|
||||
return imageCount ? this.requestedIndex() % imageCount : 0;
|
||||
});
|
||||
protected readonly hasMultipleImages = computed(() => this.images().length > 1);
|
||||
protected readonly sequentialLoadIndex = computed(() => {
|
||||
const settledIndexes = this.settledIndexes();
|
||||
|
||||
for (let index = 0; index < this.images().length; index += 1) {
|
||||
if (!settledIndexes.has(index)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
});
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
this.images();
|
||||
this.requestedIndex.set(0);
|
||||
this.loadedIndexes.set(new Set());
|
||||
this.settledIndexes.set(new Set());
|
||||
this.firstImageReadyEmitted = false;
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
const imageCount = this.images().length;
|
||||
const interval = Math.max(this.autoSlideInterval(), 1000);
|
||||
@@ -44,7 +69,11 @@ export class MainCarouselComponent {
|
||||
|
||||
const timer = window.setInterval(() => {
|
||||
if (!this.paused()) {
|
||||
this.requestedIndex.update((index) => (index + 1) % imageCount);
|
||||
this.requestedIndex.update((index) => {
|
||||
const nextIndex = (index + 1) % imageCount;
|
||||
|
||||
return this.loadedIndexes().has(nextIndex) ? nextIndex : index;
|
||||
});
|
||||
}
|
||||
}, interval);
|
||||
|
||||
@@ -62,6 +91,27 @@ export class MainCarouselComponent {
|
||||
this.paused.set(paused);
|
||||
}
|
||||
|
||||
protected imageSource(image: string, index: number): string | null {
|
||||
const shouldLoad =
|
||||
this.loadedIndexes().has(index) ||
|
||||
index === this.sequentialLoadIndex() ||
|
||||
index === this.activeIndex();
|
||||
|
||||
return shouldLoad ? image : null;
|
||||
}
|
||||
|
||||
protected handleImageLoad(index: number): void {
|
||||
this.updateIndexSet(this.loadedIndexes, index, true);
|
||||
this.updateIndexSet(this.settledIndexes, index, true);
|
||||
this.notifyFirstImageReady(index);
|
||||
}
|
||||
|
||||
protected handleImageError(index: number): void {
|
||||
this.updateIndexSet(this.loadedIndexes, index, false);
|
||||
this.updateIndexSet(this.settledIndexes, index, true);
|
||||
this.notifyFirstImageReady(index);
|
||||
}
|
||||
|
||||
protected handleKeydown(event: KeyboardEvent): void {
|
||||
if (!this.hasMultipleImages()) {
|
||||
return;
|
||||
@@ -83,4 +133,26 @@ export class MainCarouselComponent {
|
||||
protected imageAlt(index: number): string {
|
||||
return this.imageAlts()[index] || `Imagen destacada ${index + 1}`;
|
||||
}
|
||||
|
||||
private updateIndexSet(
|
||||
target: WritableSignal<ReadonlySet<number>>,
|
||||
index: number,
|
||||
present: boolean,
|
||||
): void {
|
||||
target.update((current) => {
|
||||
const updated = new Set(current);
|
||||
present ? updated.add(index) : updated.delete(index);
|
||||
|
||||
return updated;
|
||||
});
|
||||
}
|
||||
|
||||
private notifyFirstImageReady(index: number): void {
|
||||
if (index !== 0 || this.firstImageReadyEmitted) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.firstImageReadyEmitted = true;
|
||||
this.firstImageReady.emit();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user