리스트뷰-그리드뷰 전환하기

씽크패드 펑션키 밖으로 뺀 사람 찾아서 조사버리겠다… 아무튼… 포고 인벤토리 보고 생각났던건데 이제서야 함… 귀차니즘이 이렇게 무섭습니다 여러분.


https://github.com/koreanraichu/Javascript/tree/92e1d14bc15406e191c09a6cb88edc25393f0f3d/List-grid

코드는 여기 가서 봅시다. HTML이나 CSS 관련 코멘터리는 안할거임.

발단

일단 발단이 뭐냐…

위가 리스트 뷰, 아래가 그리드 뷰이다. 포켓몬고의 인벤토리는 원래 위쪽만 있었다가, 아래쪽도 일부 계정에 시범적용 후 현재는 전 계정에서 해당 설정을 할 수 있게 되었다.

일단 두 방식은 각각 장/단점이 있는데

리스트 뷰는 위의 사진처럼 아이템의 설명을 확인할 수 있고, 버리기 아이콘도 줄의 끝에 있기 떄문에 아이템이랑 거리가 있어서 아이템의 조작이 상대적으로 편하다. 하지만 도구가 많아질수록 표시하는 데 필요한 페이지 길이가 길어지기때문에 스크롤하기가 매우 귀찮고, 카테고리에 따라서는 가지고 있는 아이템의 종류와 수량을 한번에 파악하기가 어렵다는 단점이 있다. 위쪽은 도구이고 평소에는 일부 도구를 정리해서 저 정도지만, 저기에 상처약 두 종류만 추가돼도 리스트 뷰에서는 한번에 못 본다. 루어 모듈도 마찬가지.

그리드 뷰는 장단점이 리스트 뷰와 반대이다. 일단 한 눈에 아이템의 개수와 종류가 확 들어오고, 상대적으로 리스트 뷰에 비해 필요한 페이지 길이도 짧아서 스크롤 노가다를 덜 해도 된다. 하지만 아이템과 삭제버튼 간 간격이 좁기때문에 아이템을 버리려다가 다른 아이템을 선택하게 되는 사태가 자주 일어난다. 그리고 나야 본가 게임을 꽤 해봤지만 아예 포고로 처음 포켓몬을 접하거나, 아이템이 처음 보는 거라 설명이 필요할 때가 있는데, 이 때 그리드 뷰는 설명이 안보이기때문에 불편할 수도 있다.

만들어보자

일단 네이버 글자 제한때문에 HTML 코드는 여기 다 못 올린다. 그러니 같이 보고 싶으면 깃헙으로 갑시다. 위에 주소 써뒀음.

<div class="button"> <!-- 전환 버튼이 위치할 곳 -->
    <label class="switch">
        <input type="checkbox">
        <span class="slider"></span>
    </label>
</div>

위에 이 부분은 슬라이드 버튼이다. w3school에서 긁어온건데 이번에는 네모네모 버튼으로 긁어봤음. 그리고 아래쪽이 본체다.

버튼과 아이템을 wrap이 싸고 있고, 버튼 밑에 아이템이 본체인데

대충 이런 구조… 길어서 아이템족은 또 접었는데 item-wrap 안에는 아이콘과 컨텐츠가 들어있다.

그래서 이런 식으로 리스트 뷰가 적용되는거다. CSS는 후가공 몇번 했음… ㅡㅡ 옆에 있는거 독이니까 당황하지 마십쇼. 지금 이 글 쓰는 OS 리눅스임.

여기서 그리드 뷰로 바꾸는 방법은 간단하다. 첫번째, 그리드 뷰로 바꿀 때 바뀔 요소에 대해 CSS를 적용한다(grid 클래스를 주고). 두번째, JS로 토글되게 한다. 그러면 JS보다 골치 덜 아픈(안아프다고 안했음) CSS부터 들어가보자… 예전에 다크모드 포스팅 한 걸 보셨던 분들이라면 아시겠지만, 그거 비슷하게 돌아간다.

.item.grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-gap: 5px;
    align-items: center;
    justify-content: center;
}

.icon.grid {
    max-width: 100%;
    margin: 0 auto;
    font-size: 5em;
    height: auto;
    width: auto;
}

.contents.grid {
    display: none;
}

일단 여기서 그리드 뷰로 바꾸게 되면 바뀌는 거 세 가지다. 아이템(아이템 래퍼를 담고 있는 거)은 display가 그리드가 되고, 3등분 그리드로 안의 컨텐츠를 담는다. contents는 대충 설명같은 느낌인데(위에 보면 아이콘 옆에 있는 글이 contents), 그리드 뷰에서는 contents를 안 보이게 할거니까 display 속성을 none으로 했다. 그리고 아이콘의 경우 크기를 더 키웠다. 아니 쟤가 제일 잘 나가니까 당연한거 아님?

//가져올건 이 쪽
let toggleButton = document.querySelector('.slider');
let viewItem = document.querySelector('.item');
let viewCont = document.querySelectorAll('.contents');
let viewIcon = document.querySelectorAll('.icon');

//실행 코드
toggleButton.addEventListener("click", function () {
    if (viewItem.classList.contains('grid')) { //.item은 하나밖에 없어서 하나만 가져왔습니다 
        viewItem.classList.remove('grid');
    } else {
        viewItem.classList.add('grid');
    }
    viewCont.forEach(function (item) {
        if (item.classList.contains('grid')) { //컨텐츠와 아이콘은 HTML파일에 추가된 숫자만큼 여러개 있어서 forEach로 해결 
            item.classList.remove('grid');
        } else {
            item.classList.add('grid');
        }
    })
    viewIcon.forEach(function(item){
        if(item.classList.contains('grid')) {
            item.classList.remove('grid');
        } else {
            item.classList.add('grid');
        }
    })
}, false);

그러면 자바스크립트에서 이거 바꿀 수 있게 해야 한다고 했는데… 그러면 동작 지시할 버튼과 바꿀 요소를 가져와야 한다. 위에 있는 건 버튼이고, 아래 세 줄이 바꿀 요소들. forEach가 들어간것과 안 들어간 것의 차이? HTML에 뭉텅이로 있으면 forEach로 순회하면서 작업해야 다 바뀜….

나도 포고해야되니까 최대한 간결하면서도 이해하기 쉽게 설명해봅시다. item 클래스를 가지고 있는 건 HTML 파일에 하나밖에 없고, grid 클래스가 붙으면 3열짜리 그리드로 바꿀 거다. 반면 아이콘이나 콘텐츠도 별도의 클래스를 부여하고 그리드 븅 맞게 바꾸는 건 맞지만 얘네는 HTML 안에 여러개가 있다. 다행히도(?) 동적 생성은 아니고 수제로 복붙함…

아무튼 그런 과정을 거쳐서 이런 식으로 토글할 수 있다. 저거 근데 다크모드때처럼 버튼 통으로 가져왔다니 이벤트 두번 적용되더라… ㅡㅡ