All'alba vincerò

At dawn, I will win!

Javascript/Coding Apple

[Coding Apple] 캐러셀 스와이프(Carousel Swipe) / 마우스 이벤트

나디아 Nadia 2024. 3. 7. 21:43

 

 

마우스 이벤트 (mouse event)

 

 

mousedown : 마우스로 누를 때 발동

 

mouseup : 마우스를 뗄 때

 

mousemove : (해당 요소에서) 마우스를 움직일 때

  • e.clientX : 현재 마우스 위치의 X좌표
document.getElementsByClassName('slide-box')[0].addEventListener('mousemove', function(e) {
    console.log(e.clientX)
});

 

 

 

 

 

터치 이벤트 (touch event)

 

touchstart : 터치 시작 시 발동

 


touchend : 터치 종료 시 발동

  • e.changedTouches[0].clientX : 현재 터치 위치의 X좌표

touchmove : 터치 중 발동

  • e.touches[0].clientX : 현재 터치 위치의 X좌표

 

 

 

 

 

이미지(img) 드래그 가능

draggable : true는 가능, false는 불가능

<img src="xiang1.png" draggable="false">

 

 

 

 

Hammer.js

  • 마우스 & 터치 라이브러리
  • 브라우저 간 호환성을 잡아줌
  • 이벤트 리스너가 1개만 필요함
  • 스와이프, pinch, rotate 이벤트도 제공함

 

 


 

 

캐러셀 스와이프(Carousel Swipe)

 

 

 

 

구현 계획 

 

변수

  • 마우스 눌렀을 때의 좌표 변수(시작 좌표)
  • 마우스를 눌렀나 확인할 변수 - 마우스 사용 안할 때는 비활성화


1. 사진을 마우스로 눌렀을 때의 시작 좌표 구하기

 

2. 사진을 마우스로 드래그한 이동 거리만큼 옮기기

  • mousemove 좌표- mousedown 좌표    or    mouseup 좌표 - mousedown 좌표
  • 사진 이동: style.transform = `translateX(${e.clientX - 시작좌표}px)` 

 

3. 마우스를 뗐을 때 드래그한 이동 거리에 따라 보여줄 사진 결정하기

  • 사진 보여주기: style.transform = 'translateX(0vw)';
  • 끌어당기는 효과 주기: style.transition = 'all 0.5s';

(+) n번째 사진의 이동은 첫 번째 사진에서의 마우스 이동 거리를 계산하여 이동해야 한다!

  • style.transform = `translateX(calc(${e.clientX - 시작좌표}px + (-100vw)))`)

 

 

 

Vanilla JS + 축약

let 시작좌표 = 0;
let push = false;
const slideBoxes = document.querySelectorAll('.slide-slide');
const slideContainer = document.querySelector('.slide-container');

for (let i = 0; i < slideBoxes.length; i++) {
    const slide = slideBoxes[i];

    slide.addEventListener('mousedown', function(e) {
        시작좌표 = e.clientX;
        push = true;
    });

    slide.addEventListener('mousemove', function(e) { // 이미지 드래그 효과
        if (push) {
            const offsetX = i * -100;
            slideContainer.style.transform = `translateX(calc(${e.clientX - 시작좌표}px + (${offsetX}vw)))`;
        }
    });

    slide.addEventListener('mouseup', function(e) {
        push = false;

        let targetIndex; // 이미지 순서 변수 생성

        if (e.clientX - 시작좌표 < -100) {
            targetIndex = i + 1; // 다음 사진 보여주기
            if (targetIndex === slideBoxes.length) { // 마지막 사진은 첫 번째 사진으로 순환
                targetIndex = 0; 
            }
        } else if (e.clientX - 시작좌표 > 100) {
            targetIndex = i - 1; // 이전 사진 보여주기
            if (targetIndex === -1) { // 첫 번째 사진은 마지막 사진으로 순환
                targetIndex = slideBoxes.length - 1; 
            }
        } else {
            targetIndex = i;
        }

		// 이미지 이동시키기
        const targetTransform = targetIndex * -100;

        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = `translateX(${targetTransform}vw)`;


        setTimeout(() => { // 애니메이션 렉 제거
            slideContainer.style.transition = 'none';
        }, 500);
    });
}

 

 

 

Vanilla JS

let 시작좌표 = 0;
let push = false; // 마우스 눌렀나 확인하는 변수

// 첫 번째 사진
document.querySelectorAll('.slide-box')[0].addEventListener('mousedown', function(e) {
    시작좌표 = e.clientX;
    push = true;
});

document.querySelectorAll('.slide-box')[0].addEventListener('mousemove', function(e) {
    if (push) {
        document.querySelector('.slide-container').style.transform = `translateX(${e.clientX - 시작좌표}px)`;
    }
});

document.querySelectorAll('.slide-box')[0].addEventListener('mouseup', function(e) {
    push = false;

    // 이동 거리 계산 후 -> 기준 사진 or 다음 사진 결정
    if (e.clientX - 시작좌표 < -100) { // 다음 사진
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(-100vw)';
    } else if (e.clientX - 시작좌표 > 100) { // 왼쪽으로 스와이프 시 이전 사진
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(-200vw)';
    } else { // 이전 사진
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(0vw)';
    }

    setTimeout(() => {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'none';
    }, 500);
});


// 두 번째 사진
document.querySelectorAll('.slide-box')[1].addEventListener('mousedown', function(e) {
    시작좌표 = e.clientX;
    push = true;
});

document.querySelectorAll('.slide-box')[1].addEventListener('mousemove', function(e) {
    if (push) {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transform = `translateX(calc(${e.clientX - 시작좌표}px + (-100vw)))`;
    }
});

document.querySelectorAll('.slide-box')[1].addEventListener('mouseup', function(e) {
    push = false;

    if (e.clientX - 시작좌표 < -100) {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(-200vw)';
    } else if (e.clientX - 시작좌표 > 100) {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(0vw)';
    } else {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(-100vw)';
    }

    setTimeout(() => {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'none';
    }, 500);
});


// 세 번째 사진
document.querySelectorAll('.slide-box')[2].addEventListener('mousedown', function(e) {
    시작좌표 = e.clientX;
    push = true;
});

document.querySelectorAll('.slide-box')[2].addEventListener('mousemove', function(e) {
    if (push) {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transform = `translateX(calc(${e.clientX - 시작좌표}px + (-200vw)))`;
    }
});

document.querySelectorAll('.slide-box')[2].addEventListener('mouseup', function(e) {
    push = false;

    if (e.clientX - 시작좌표 < -100) {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(0vw)';
    } else if (e.clientX - 시작좌표 > 100) {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(-100vw)';
    } else {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'all 0.5s';
        slideContainer.style.transform = 'translateX(-200vw)';
    }

    setTimeout(() => {
        const slideContainer = document.querySelector('.slide-container');
        slideContainer.style.transition = 'none';
    }, 500);
});

 

 

 

 

jQuery

var 시작좌표 = 0;
var push = false; // 마우스 눌렀나 확인하는 변수

$('.slide-box').eq(0).on('mousedown', function(e){
    시작좌표 = e.clientX;
    push = true;
});


$('.slide-box').eq(0).on('mousemove', function(e){

    // 마우스 눌렀을 때 움직이도록 
    if (push == true) {
        $('.slide-container').css('transform', `translateX( ${e.clientX - 시작좌표}px )`) 
    }
});


$('.slide-box').eq(0).on('mouseup', function(e){
    // 마우스 떼면 기능 X
    push = false;

    // 이동 거리 계산 후 -> 기준 사진 or 다음 사진 결정
    if (e.clientX - 시작좌표 < -100) {
        $('.slide-container') // 다음 사진
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(-100vw)');
    } else if (e.clientX - 시작좌표 > 100) { // 왼쪽으로 드래그 시 마지막 사진 보여주기
        $('.slide-container')
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(-200vw)');
    } else {
        $('.slide-container') // 기존 사진
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(0vw)');
    }

    setTimeout(() => {
        $('.slide-container').css('transition', 'none')
    }, 500)
});


//-----------------2번째 사진------------------------
$('.slide-box').eq(1).on('mousedown', function(e){
    시작좌표 = e.clientX;
    push = true;
});


$('.slide-box').eq(1).on('mousemove', function(e){

    if (push == true) {
        // 두 번째 사진의 이동은 첫 번째 사진에서의 마우스 이동 거리를 계산하여 이동해야 한다.
        $('.slide-container').css('transform', `translateX(calc(${e.clientX - 시작좌표}px + (-100vw)))`)
    }
});


$('.slide-box').eq(1).on('mouseup', function(e){
    push = false;

    if (e.clientX - 시작좌표 < -100) {
        $('.slide-container')
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(-200vw)');
    } else if (e.clientX - 시작좌표 > 100) { // 왼쪽으로 드래그 시 이전 사진
        $('.slide-container')
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(0vw)');
    } else {
        $('.slide-container')
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(-100vw)');
    }

    setTimeout(() => {
        $('.slide-container').css('transition', 'none')
    }, 500)
});


//-----------------3번째 사진------------------------
$('.slide-box').eq(2).on('mousedown', function(e){
    시작좌표 = e.clientX;
    push = true;
});


$('.slide-box').eq(2).on('mousemove', function(e){

    if (push == true) {
        // 세 번째 사진의 이동은 첫 번째 사진에서의 마우스 이동 거리를 계산하여 이동해야 한다.
        $('.slide-container').css('transform', `translateX(calc(${e.clientX - 시작좌표}px + (-200vw)))`) 
    }
});


$('.slide-box').eq(2).on('mouseup', function(e){
    push = false;

    if (e.clientX - 시작좌표 < -100) {
        $('.slide-container')
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(0vw)');
    } else if (e.clientX - 시작좌표 > 100) { // 왼쪽으로 드래그 시 이전 사진
        $('.slide-container')
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(-100vw)');
    } else { 
        $('.slide-container')
        .css('transition', 'all 0.5s')
        .css('transform', 'translateX(-200vw)');
    }
    
    setTimeout(() => {
        $('.slide-container').css('transition', 'none')
    }, 500)
});

 

 

 

 

 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC&display=swap');
    </style>
    <link rel="stylesheet" href="main.css" />
</head>
<body>
    <div style="overflow: hidden;">
        <div class="slide-container">
            <div class="slide-box">
                <img src="xiang1.png" draggable="false">
            </div>
            <div class="slide-box">
                <img src="xiang2.png"  draggable="false">
            </div>
            <div class="slide-box">
                <img src="xiang3.png"  draggable="false">
            </div>
        </div>
    </div>
    <script src="index.js"></script>
</body>
</html>

 

 

 

main.css

.slide-container {
    width: 300vw; 
}

.slide-box {
    width: 100vw;
    float: left;
}

.slide-box img {
    width: 100%;
}

 

 

 

 


 

 

깃허브

https://github.com/kwonboryong/CodingApple/tree/main/carousel-swipe

 

 

 


 

 

출처

코딩애플