[JS] 인스타그램처럼 사진 넘기기

ziwww·2024년 4월 2일

개발

목록 보기
8/14
post-thumbnail

Intro

이번에 시작한 프로젝트는 집밥 소개를 위한 SNS를 만드는 프로젝트이다.
SNS이기 때문에 인스타그램을 많이 참고하였고, 나는 거기서 게시판, 메인페이지 부분을 맡았다.
따라서 인스타그램처럼 사진을 하나하나 넘길 수 있는 기능을 만들어야 한다.

처음에는 이 기능을 구현하기 위해서 슬릭 슬라이더라는 것을 사용했었다.
하지만 외부 API를 사용하는 것이기 때문에 마음대로 사용하는 것이 너무 어려웠고 사진도 제대로 뜨지 않았다... 그래서 그냥 직접 만들기로 했다.

처음 방식

처음에 만들었던 방식이다.

let boardSlideIndex;

//slide 사용하는 곳이 여러 곳이기 때문에 새로고침될 때마다 0으로 초기화 필요하다.
document.addEventListener('DOMContentLoaded', function () {
    boardSlideIndex = 0;
});

function prevSlide(button) {
    //현재 버튼이 속한 container 찾기
    const imageContainer = button.closest('.image-container');
    const imageList = imageContainer.querySelector('.image-list');
    const imageItem = imageContainer.querySelectorAll('.image-item');
    // 음수가 되지 않게 imageItem.length를 더해주었다.
    boardSlideIndex = (boardSlideIndex - 1 + imageItem.length) % imageItem.length;
    //왼쪽방향으로 이동
    const newPosition = -boardSlideIndex * imageItem[0].offsetWidth;
    imageList.style.transform = `translateX(${newPosition}px)`;
}

function nextSlide(button) {
    //현재 버튼이 속한 container 찾기
    const imageContainer = button.closest('.image-container');
    const imageList = imageContainer.querySelector('.image-list');
    const imageItem = imageContainer.querySelectorAll('.image-item');
    // 현재 위치에서 1칸 이동, 만약 뒤에 더 이미지가 없다면 처음으로 이동
    boardSlideIndex = (boardSlideIndex + 1) % imageItem.length;
    //imageWidth만큼 왼쪽 방향으로 이동
    const newPosition = -boardSlideIndex * imageItem[0].offsetWidth;
    imageList.style.transform = `translateX(${newPosition}px)`;
}

코드를 설명하자면

let boardSlideIndex;

몇 번째 사진을 볼 것인지 구분하는 index 변수이다.

function prevSlide(button) {
    //현재 버튼이 속한 container 찾기
    const imageContainer = button.closest('.image-container');
    const imageList = imageContainer.querySelector('.image-list');
    const imageItem = imageContainer.querySelectorAll('.image-item');
    // 음수가 되지 않게 imageItem.length를 더해주었다.
    boardSlideIndex = (boardSlideIndex - 1 + imageItem.length) % imageItem.length;
    //왼쪽방향으로 이동
    const newPosition = -boardSlideIndex * imageItem[0].offsetWidth;
    imageList.style.transform = `translateX(${newPosition}px)`;
}

이전 사진보기 버튼이다.

  • const imageContainer = button.closest('.image-container')는 현재 누른 버튼에 속해있는 이미지들을 포함하고 있는 태그를 가져오는 것이다. 컨테이너를 가져온 이유는, 사진 하나하나 요소와 요소들이 담긴 list를 가져오기 위해서 이다.
  • 다음 코드들은 container를 이용해서 요소 하나(image-item), 요소들(image-list)를 가져온다.
  • boardSlideIndex = (boardSlideIndex - 1 + imageItem.length) % imageItem.length는 사진의 index를 결정하는 코드이다.
    만약 3개의 사진이 있고 첫번째 사진에서 전 버튼을 눌렀다면 (0-1+3)%3=2 즉, 마지막 사진으로 이동이 된다.
  • const newPosition이 이동을 하게 하는 변수이다. 이동해야하는 위치를 정해준다.
  • -boardSlideIndex * imageItem[0].offsetWidth= 사진 요소의 width를 index만큼 준다. (사진들은 똑같은 width를 가지고 있고 index로 몇 개의 사진을 넘겨야하는 지 결정해준다.)
  • imageList.style.transform = translateX(${newPosition}px)= imageList는 사진들이 가로로 쭉 이어져있는 형태이다. translateX로 위치를 이동하게하여 사진을 x축 방향으로 이동하게 끔한다. 음수로 이동하기 때문에 왼쪽으로 이동하게된다.

nextSlide도 마찬가지의 로직이다.

이러한 로직으로 처음에는 코드를 짰지만, 한 가지 문제점이 생겼다.
그냥 게시물일 경우 하나의 imageList밖에 없기 때문에 제대로 잘 동작한다.

하지만, 메인페이지일 경우 여러 imageList가 있지만 boardSlideIndex를 공유하기 때문에 제대로 동작하지 않았다.

이걸 해결하기 위해서는 boardSlideIndex를 공유하지 않아야한다.

해결한 방법

해결한 방식은 boardSlideIndex를 리스트로 관리 하는 것이다.

전체코드

// 객체를 사용하여 각 게시물의 슬라이드 인덱스 관리
const boardSlideIndex = {};

//slide 사용하는 곳이 여러 곳이기 때문에 새로고침될 때마다 0으로 초기화 필요하다.(board, main)
document.addEventListener('DOMContentLoaded', function () {
    for (let key in boardSlideIndex) {
        delete boardSlideIndex[key];
    }
});

function prevSlide(boardId, button) {
    let currentIndex = boardSlideIndex[boardId] || 0; // 해당 게시물의 슬라이드 인덱스를 가져오거나, 없으면 0으로 초기화
    const imageItem = button.closest('.image-container').querySelectorAll('.image-item').length; //게시물에 등록된 사진의 개수
    // 음수가 되지 않게 imageItem.length를 더해주었다.
    currentIndex = (currentIndex - 1 + imageItem) % imageItem;
    moveSlide(boardId, currentIndex, button);
}

function nextSlide(boardId, button) {
    let currentIndex = boardSlideIndex[boardId] || 0; // 해당 게시물의 슬라이드 인덱스를 가져오거나, 없으면 0으로 초기화
    const imageItem = button.closest('.image-container').querySelectorAll('.image-item').length;//게시물에 등록된 사진의 개수
    // 현재 위치에서 1칸 이동, 만약 뒤에 더 이미지가 없다면 처음으로 이동
    currentIndex = (currentIndex + 1) % imageItem;
    moveSlide(boardId, currentIndex, button);
}

function moveSlide(boardId, newIndex, button) {
    const imageList = button.closest('.image-container').querySelector('.image-list');
    const imageWidth = imageList.querySelector('.image-item').offsetWidth;
    const newPosition = -newIndex * imageWidth;
    imageList.style.transform = `translateX(${newPosition}px)`;
    boardSlideIndex[boardId] = newIndex; // 해당 게시물의 슬라이드 인덱스 업데이트
}

하나하나 설명하자면,

function prevSlide(boardId, button) {
    let currentIndex = boardSlideIndex[boardId] || 0; // 해당 게시물의 슬라이드 인덱스를 가져오거나, 없으면 0으로 초기화
    const imageItem = button.closest('.image-container').querySelectorAll('.image-item').length; //게시물에 등록된 사진의 개수
    // 음수가 되지 않게 imageItem.length를 더해주었다.
    currentIndex = (currentIndex - 1 + imageItem) % imageItem;
    moveSlide(boardId, currentIndex, button);
}
  • let currentIndex = boardSlideIndex[boardId] || 0 = 만약 boardSlideIndex리스트에 해당 게시물의 id에 해당하는 값이 없다면(옆으로 넘기는 버튼을 처음 눌렀다면) 0을 넣어주고 아니라면 기존의 값을 사용한다. 이것으로 공유를 안하게 되는 것이다.
  • 나머지는 똑같은 로직이다.

nextSlide도 똑같은 방식이다.

function moveSlide(boardId, newIndex, button) {
    const imageList = button.closest('.image-container').querySelector('.image-list');
    const imageWidth = imageList.querySelector('.image-item').offsetWidth;
    const newPosition = -newIndex * imageWidth;
    imageList.style.transform = `translateX(${newPosition}px)`;
    boardSlideIndex[boardId] = newIndex; // 해당 게시물의 슬라이드 인덱스 업데이트
}

이렇게 따로 function을 만들어 준 이유는 코드가 preSlide와 nextSlide의 사진 넘기는 코드가 중복이기 때문에 따로 빼주었다.


```javascript document.addEventListener('DOMContentLoaded', function () { for (let key in boardSlideIndex) { delete boardSlideIndex[key]; } }); ``` 메인 페이지에서 좋아요순, 팔로우순 이런 정렬을 사용할 때 비동기 방식으로 사용하기 때문에 boardSlideIndex는 초기화되지 않는다. 그렇기 때문에 초기화하는 로직이 필요하다.

이렇게 만들어주니 인스타처럼 제대로 동작하였다..!

profile
반갑습니다. 오늘도 즐거운 하루입니다.

0개의 댓글