Как переместить слайд с помощью мыши и на телефоне?CSS

Разбираемся в CSS
Ответить
Anonymous
 Как переместить слайд с помощью мыши и на телефоне?

Сообщение Anonymous »

Как реализовать решение, которое позволит пользователям перемещаться по слайдам с помощью мыши на настольных устройствах и с помощью сенсорных жестов (проведение пальцем) на мобильных устройствах, не полагаясь на сторонние библиотеки? Мне нужно, чтобы навигация была интуитивно понятной и плавной, с поддержкой как перетаскивания мышью, так и событий касания. Цель — создать адаптивный слайдер, который будет без проблем работать на экранах разных размеров и при различных методах ввода.






























    CSS:
    ol {
    list-style: none;
    }

    .slider_robots {
    display: flex;
    flex-direction: column;
    align-items: center;

    padding: 80px 0 0 20px;
    margin: 0 20px 80px 0;
    }

    .slider_robots_container {
    position: relative;

    width: clamp(414px, 100%, 1282px);

    margin-bottom: 45px;

    overflow: hidden;
    }

    .slider_btn_container {
    position: absolute;
    z-index: 1000;

    display: flex;
    align-items: center;
    justify-content: center;

    background-color: #f7f7f7;
    border-radius: 100%;
    width: 54px;
    height: 54px;

    cursor: pointer;
    }

    .btn_prev_position {
    left: 0;
    top: 380px;
    }
    .btn_next_position {
    right: 0;
    top: 380px;
    }

    .slider_btn {
    width: 11px;
    height: 11px;
    border-top: 2px solid #6a768c;
    border-right: 2px solid #6a768c;
    }
    .btn_prev {
    transform: rotate(-135deg);
    margin-left: 3px;
    }
    .btn_next {
    transform: rotate(45deg);
    margin-right: 3px;
    }

    .slider_robots_track {
    display: flex;

    padding: 0 15px;

    transition: transform .5s;
    }

    .slider_robot_wrapper {
    display: flex;
    flex-direction: column;
    flex-grow: 0;
    flex-shrink: 0;
    flex-basis: calc((100% - 2 * 20px) / 3);

    gap: 25px;
    padding-right: 20px;

    pointer-events: none;
    }

    .slide_robot {
    width: 414px;
    height: 414px;
    border-radius: 12px;

    pointer-events: auto;
    }

    .pagination_circles_container {
    display: flex;
    justify-content: center;
    width: 100%;
    gap: 24px;
    }

    .pagination_circle {
    background-color: #b8edb7;
    border-radius: 100%;
    width: 10px;
    height: 10px;

    cursor: pointer;
    }

    .circle_active {
    background-color: #b8edb7;
    width: 10px;
    height: 10px;
    border-radius: 100%;
    box-shadow: 0 0 0 7px #447355;
    }

    @media screen and (max-width: 1024px) {

    .slider_robots_container {
    width: clamp(462px, 100%, 942px);
    }

    .slider_robot_wrapper {
    flex-basis: calc((100% - 20px) / 2);
    }

    }

    @media screen and (max-width: 768px) {

    .slider_robots_container {
    width: clamp(100px, 100%, 687px);
    }

    .slider_robot_wrapper {
    flex-basis: 100%;
    }

    }

    js:
    const paginationCirclesContainerEl = document.querySelector('.pagination_circles_container');
    const btnPrevPositionEl = document.querySelector('.btn_prev_position');
    const btnNextPositionEl = document.querySelector('.btn_next_position');
    const sliderRobotsTrackEl = document.querySelector('.slider_robots_track');
    const sliderRobotWrapperEls = [...document.querySelectorAll('.slider_robot_wrapper')];

    // Variables for working with slides
    const visibleSlidesCount = 3;
    let currentSlideIndex = visibleSlidesCount;
    let isAnimating = false;

    // Creating pagination circles equal to the number of slides
    const paginationCircles = [];

    const createPaginationCircles = () => {
    const li = document.createElement('li');
    li.className = 'pagination_circle';
    paginationCirclesContainerEl.appendChild(li);
    paginationCircles.push(li);
    };

    const addPagination = () => {
    sliderRobotWrapperEls.forEach(createPaginationCircles);
    paginationCircles[0].classList.add('circle_active');
    };
    addPagination();

    // Base slide width
    let slideWidth = sliderRobotWrapperEls[0].offsetWidth;

    // Cloning the first three slides
    const lastThreeSlides = sliderRobotWrapperEls.slice(0, visibleSlidesCount);
    lastThreeSlides.forEach(slideEl => {
    const clone = slideEl.cloneNode(true);
    sliderRobotsTrackEl.append(clone);
    });

    // Cloning the last three slides
    const firstThreeSlides = sliderRobotWrapperEls.slice(-visibleSlidesCount);
    firstThreeSlides.forEach(slideEl => {
    const clone = slideEl.cloneNode(true);
    sliderRobotsTrackEl.insertBefore(clone, sliderRobotWrapperEls[0]);
    });

    // New list of slides (12)
    const allSlides = [...document.querySelectorAll('.slider_robot_wrapper')];

    let isDragging = false;
    let startX = 0;
    let currentTranslate = 0;
    let prevTranslate = 0;

    sliderRobotsTrackEl.addEventListener('mousedown', e => {
    isDragging = true;
    startX = e.clientX;
    });

    sliderRobotsTrackEl.addEventListener('mousemove', e => {
    if (!isDragging) return;

    const currentX = e.clientX;
    const diffX = currentX - startX;
    currentTranslate = prevTranslate + diffX;

    updateSliderPosition();
    });

    sliderRobotsTrackEl.addEventListener('mouseup', e => {
    if (!isDragging) return;

    isDragging = false;
    prevTranslate = currentTranslate;
    });

    // Dynamically update the slide width on resize
    const updateSlideWidth = () => {
    slideWidth = allSlides[0].offsetWidth;
    updateSliderPosition();
    };
    window.addEventListener('resize', updateSlideWidth);

    // Move the track with slides
    const updateSliderPosition = (withTransition = true, index) => {

    if (index) {
    removeActiveClass(currentSlideIndex);
    currentSlideIndex = index;
    addActiveClass(currentSlideIndex);
    }

    const offset = -currentSlideIndex * slideWidth;

    sliderRobotsTrackEl.style.transition = withTransition ? 'transform .5s' : 'none';
    sliderRobotsTrackEl.style.transform = `translate3d(${offset}px, 0px, 0px)`;
    };

    // Navigation through pagination circles
    paginationCircles.forEach((circleEl, index) => {
    circleEl.addEventListener('click', () => {
    updateSliderPosition(true, index + visibleSlidesCount);
    });
    });

    // Add active circle class to the current slide
    const addActiveClass = (currentSlideIndexCircle) => {
    let normalizedIndex;

    if (currentSlideIndexCircle) {
    normalizedIndex = (currentSlideIndexCircle - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    } else {
    normalizedIndex = (currentSlideIndex - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    }

    paginationCircles[normalizedIndex].classList.add('circle_active');
    };

    // Remove active circle class from the previous slide
    const removeActiveClass = (currentSlideIndexCircle) => {
    let normalizedIndex;

    if (currentSlideIndexCircle) {
    normalizedIndex = (currentSlideIndexCircle - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    } else {
    normalizedIndex = (currentSlideIndex - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    }
    paginationCircles[normalizedIndex].classList.remove('circle_active');
    };

    // Show the next slide
    const nextSlide = () => {
    // Block click until animation is finished
    if (isAnimating) return;
    isAnimating = true;
    setTimeout(() => {
    isAnimating = false;
    }, 500);

    removeActiveClass();

    currentSlideIndex++;
    updateSliderPosition();

    addActiveClass();

    // Quick rewind when reaching the last clone
    if (currentSlideIndex === allSlides.length - visibleSlidesCount) {
    setTimeout(() => {
    currentSlideIndex = visibleSlidesCount;
    updateSliderPosition(false);

    }, 500);
    }
    };

    // Show the previous slide
    const prevSlide = () => {
    // Block click until animation is finished
    if (isAnimating) return;
    isAnimating = true;
    setTimeout(() => {
    isAnimating = false;
    }, 500);

    removeActiveClass();

    currentSlideIndex--;
    updateSliderPosition();

    addActiveClass();

    // Quick rewind when reaching the first clone
    if (currentSlideIndex === 0) {
    setTimeout(() => {
    currentSlideIndex = allSlides.length - visibleSlidesCount * 2;
    updateSliderPosition(false);

    }, 500);
    }
    };

    // Event handlers for the buttons
    btnNextPositionEl.addEventListener('click', nextSlide);
    btnPrevPositionEl.addEventListener('click', prevSlide);

    // Initialize the initial position of the slider
    updateSliderPosition(false);


    Подробнее здесь: https://stackoverflow.com/questions/793 ... n-my-phone
    Ответить

    Быстрый ответ

    Изменение регистра текста: 
    Смайлики
    :) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
    Ещё смайлики…
       
    К этому ответу прикреплено по крайней мере одно вложение.

    Если вы не хотите добавлять вложения, оставьте поля пустыми.

    Максимально разрешённый размер вложения: 15 МБ.

    Вернуться в «CSS»