Hero image
Inicio > Blog > Post

Creando un componente de carrusel interactivo con Qwik

Introducción.

En el mundo del desarrollo web, a menudo nos encontramos con la necesidad de implementar carruseles interactivos en nuestras aplicaciones. Estos carruseles son útiles para mostrar una serie de elementos de manera dinámica y permitir a los usuarios navegar entre ellos. En este artículo, aprenderemos cómo crear un componente de carrusel utilizando Qwik, un framework de JavaScript para construir interfaces de usuario eficientes.

Qwik es un framework moderno de JavaScript resumible que renderiza el HTML del lado del servidor para optimizar el rendimiento. En este tutorial, utilizaremos Qwik para construir un componente de carrusel personalizable y fácil de usar.

Configuración del proyecto:

Antes de comenzar, asegúrate de tener un proyecto de Qwik configurado y listo para usar. Puedes instalar Qwik utilizando npm o yarn. Asegúrate de tener las dependencias necesarias instaladas en tu proyecto.

Creando el componente de carrusel:

Comencemos por importar las dependencias necesarias para nuestro componente de carrusel:

import { 
    type QwikMouseEvent, 
    component$, 
    useSignal, $, 
    useVisibleTask$, Slot 
} from "@builder.io/qwik";
import { TbChevronLeft, TbChevronRight } from "@qwikest/icons/tablericons";

Definamos los tipos y las interfaces que utilizaremos en nuestro componente:

type SliderParam = {
    slidesPerView: number,
    spaceBetween: number
}

interface CarouselProps {
    sliderParam: SliderParam,
}

Ahora, crearemos nuestro componente de carrusel utilizando la función component$ proporcionada por Qwik:

export const Carousel = component$(({ sliderParam }: CarouselProps) => {
    // Aquí irá el código del componente
});

Dentro de nuestro componente, utilizaremos las señales proporcionadas por Qwik para gestionar el estado y la interacción del carrusel:

const sliderRef = useSignal<HTMLDivElement>();
const widthSlider = useSignal<number>(0);
const isDragging = useSignal(false);
const startX = useSignal<number>(0);
const startScrollLeft = useSignal<number>(0);

Estas señales nos permitirán mantener un seguimiento del estado del carrusel, la posición inicial del arrastre y el desplazamiento inicial.

A continuación, definiremos las funciones de manejo de eventos para el arrastre del carrusel:

const dragStart = $((e: QwikMouseEvent<HTMLDivElement, MouseEvent>) => {
    isDragging.value = true;
    sliderRef.value?.classList.add("dragging");
    startX.value = e.pageX;
    startScrollLeft.value = sliderRef.value?.scrollLeft || 0;
});

const dragStop = $(() => {
    isDragging.value = false;
    sliderRef.value?.classList.remove("dragging");
});

const dragging = $((e: QwikMouseEvent<HTMLDivElement, MouseEvent>) => {
    if (sliderRef.value == undefined || !isDragging.value) return;
    sliderRef.value.scrollLeft = startScrollLeft.value - (e.pageX - startX.value)
});

Estas funciones se encargarán de actualizar la posición del carrusel mientras se arrastra y de manejar los eventos de inicio y finalización del arrastre.

También implementaremos las funciones para desplazarse al siguiente y al anterior elemento del carrusel:

const nextSlider = $(() => {
    if (sliderRef.value == undefined) return;
    sliderRef.value.scrollLeft += widthSlider.value / sliderParam.slidesPerView;
});

const prevSlider = $(() => {
    if (sliderRef.value == undefined) return;
    sliderRef.value.scrollLeft -= widthSlider.value / sliderParam.slidesPerView;
});

Estas funciones actualizarán la posición del carrusel para mostrar el siguiente o el elemento anterior, según el número de elementos visibles especificado en slidesPerView.

A continuación, utilizaremos useVisibleTask$ un hook proporcionado por Qwik, para realizar algunas tareas cuando el carrusel sea visible en la página:

useVisibleTask$(() => {
    if (sliderRef.value) {
        widthSlider.value = sliderRef.value.clientWidth;
    }
    // hacemos que todos los elemetos no sean arrastrables
    const applyDraggable = (element: Element) => {
        element.setAttribute('draggable', 'false');
        const children = element.children;
        for (let i = 0; i < children.length; i++) {
            applyDraggable(children[i]);
        }
    }

    const divElement = sliderRef.value?.querySelectorAll('.slider-slide');
    
    if (divElement) {
        divElement.forEach(el => {
            applyDraggable(el);
        })
    }
    
});

Dentro de useVisibleTask$, podemos realizar cualquier tarea adicional, como obtener el ancho del carrusel y aplicar la lógica necesaria para que los elementos sean arrastrables o realicen otras acciones específicas.

A continuación, crearemos la estructura del carrusel utilizando JSX:

return (
    <div class="slider">
        <div
            class="slider-wrapper"
            style={{
                gridAutoColumns: `${(widthSlider.value - (sliderParam.spaceBetween * (sliderParam.slidesPerView - 1))) / sliderParam.slidesPerView}px`,
                gap: `${sliderParam.spaceBetween}px`
            }}
            ref={sliderRef}
            onMouseMove$={dragging}
            onMouseDown$={dragStart}
            onMouseUp$={dragStop}
            onMouseLeave$={dragStop}
        >
            <Slot />
        </div>
        <div class="slider-button-next" onClick$={nextSlider}>
            <TbChevronRight />
        </div>
        <div class="slider-button-prev" onClick$={prevSlider} >
            <TbChevronLeft />
        </div>
    </div>
);

En este código JSX, creamos la estructura del carrusel con la clase CSS correspondiente. El contenedor principal contiene el elemento desplazable y los botones de navegación para ir al siguiente y al anterior elemento. También utilizamos la etiqueta para permitir que los elementos del carrusel se inserten dentro del componente desde fuera.

Finalmente, definimos las clases de CSS que utilizaremos para estilizar nuestro componente de carrusel:

.slider {
  position: relative;
  max-width: 1200px;
  width: 100%;
}


.slider-wrapper {
  box-sizing: border-box;
  display: grid;    
  grid-auto-flow: column;
  grid-auto-columns: calc((100% / 1) - 23px);
  gap: 24px;
  overflow: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: 0;
}
.slider-wrapper::-webkit-scrollbar{
  display: none;
}

.slider-wrapper.dragging {
  scroll-snap-type: none;
  scroll-behavior: auto;
}
.slider-slide{
  scroll-snap-align: start;
  cursor: pointer;
  height: 100%;
}
.slider-wrapper.dragging .slider-slide{
  cursor: grab;
  user-select: none;
  /* pointer-events: none; */
}

.slider-button-next,
.slider-button-prev {
  position: absolute;
  top: -3.8em;
  z-index: 10;
  cursor: pointer;
  background-color: var(--first-color-alt);
  border: 1px solid var(--border-color);
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--first-color);
  font-size: var(--tiny-font-size);

  &>svg {
    font-size: 1.3em;
  }
}

.slider-button-prev {
  left: initial;
  right: 2.5rem;
}

.slider-button-next {
  right: 0;
}

En este código CSS, definimos las clases para el contenedor principal del carrusel, el contenedor desplazable, los elementos del carrusel y los botones de navegación.

Conclusión:

En este artículo, aprendimos cómo utilizar Qwik para crear un componente de carrusel interactivo. Exploramos cómo utilizar las señales y las tareas proporcionadas por Qwik para gestionar el estado y la interacción del carrusel. También vimos cómo implementar funciones de arrastre y navegación para hacer que el carrusel sea fácil de usar. Con este conocimiento, ahora puedes crear tus propios componentes de carrusel personalizados utilizando Qwik.

Recuerda que este código es solo un ejemplo y puede adaptarse según tus necesidades y preferencias. ¡Experimenta y diviértete construyendo carruseles interactivos!


Mis redes sociales

Si tienes alguna sugerencia o comentaria puedes contactarme en mis redes sociales.