자바스크립트로 리스트를 만들어버림

LSA·2022년 2월 23일
1

이걸해냄

목록 보기
2/8

webucks project_220222

저번 로그인 페이지에서 로그인하면 넘어오게 되는 그 페이지입니다.

1. 화면 구현


총 12장의 이미지가 들어있는 갤러리입니다.

2. 기능 구현

  • 커피 사진과 이름은 모두 다르게 해주세요.
  • 반응형을 고려하지 않으셔도 괜찮습니다.
    • 반응형을 고려하신다면 커피 리스트는 flex-wrap 혹은 grid를 활용해주세요.
  • 커피 이미지에 마우스를 호버했을 때 이미지를 확대해주세요.

사실 위의 조건들은 css단계에서 처리 가능한 기능이라서 크게 어렵지 않아요.
제가 어려웠던건..

사진 12개를 일일이 html로 작성하기 귀찮은데, 이걸 어떻게 자바스크립트로 처리할 방법 없을까?
였습니다.

2-1. 흐름 설정

리스트 html 생성

  1. 커피의 종류별로 객체를 생성한다. 커피의 데이터는 이미지경로와 이름으로 구성되어 있다.
    • ex) 콜드 브루 커피= {name:'나이트로 바닐라 크림',imgUrl:'/img/cb-01.jpg'}
      브루드 커피= {name:'아이스 커피',imgUrl:'/img/b-01.jpg'}
  2. 객체의 이름과 이미지 경로를 각각 읽어와 <ul> 의 하위 태그로 구성한다.
  • 갤러리 1개의 HTML 구조
    <section class="coffee-section cold-brew">
    	<h3 class="coffee-section-title">콜드 브루 커피 ☕</h3>
       <ul class="coffee-gall">
         <!--여기부터-->
            <li>
                <a class="coffee-thumbnail" href="#">
                	<div class="coffee-img"><img src="img/cb-01.jpg" alt="cb-01"/></div>
                   <p class="coffee-name">커피이름</p>
                </a>
            </li>
         <!--여기까지 생성할 부분-->
        </ul>                          
    </section>

2-2. 코드 작성

변수 및 객체 지정

const coldBrewList = [{
    name: '나이트로 바닐라 크림',
    imgUrl: 'img/cb-01.jpg'
}, {
    name: '나이트로 콜드 브루',
    imgUrl: 'img/cb-02.jpg'
}, {
    name: '돌체 콜드 브루',
    imgUrl: 'img/cb-03.jpg'
}, {
    name: '바닐라 크림 콜드 브루',
    imgUrl: 'img/cb-04.jpg'
}, {
    name: '벨벳 다크 모카 나이트로',
    imgUrl: 'img/cb-05.jpg'
}, {
    name: '시그니처 더 블랙 콜드 브루',
    imgUrl: 'img/cb-06.jpg'
}, {
    name: '제주 비자림 콜드 브루',
    imgUrl: 'img/cb-07.jpg'
}, {
    name: '콜드 브루',
    imgUrl: 'img/cb-08.jpg'
}, {
    name: '콜드 브루 몰트',
    imgUrl: 'img/cb-09.jpg'
}, {
    name: '콜드 브루 오트 라떼',
    imgUrl: 'img/cb-10.jpg'
}]

const brewedList = [{
    name: '아이스 커피',
    imgUrl: 'img/b-01.jpg'
}, {
    name: '오늘의 커피',
    imgUrl: 'img/b-02.jpg'
}]

이렇게 배열로 한번 감싸고 안에 객체 여러개를 넣었습니다.

const coldBrewGall = document.querySelector('.cold-brew .coffee-gall'),
    brewedGall = document.querySelector('.brewed .coffee-gall');

그리고 태그가 들어갈 곳인 각각의 갤러리 ul태그를 변수로 지정해줍니다.

일단 객체 내 데이터를 뽑아내보자

return 명령문은 값을 하나만 반환할 수 있습니다.
마음만으로는 객체 내의 이름과 url을 한꺼번에 뽑아내고 싶은데 return의 특성때문에 이름 따로, url 따로 뽑아내기로 했어요.

function exportName(data) {
    let coffeeName = [];
    for (let key in data) {
        coffeeName.push(data[key]['name']);
    }
    return coffeeName;
}

function exportUrl(data) {
    let coffeeImg = [];
    for (let key in data) {
        coffeeImg.push(data[key]['imgUrl']);
    }
    return coffeeImg;
}

파라미터 data에 위에서 지정해준 객체 coldBrewList,brewedList가 들어갈거에요.
이제 저기서 객체들을 차례로 확인하면서 key값인 nameimgUrl들의 value를 뽑아내 배열로 반환합니다.

뽑아낸 데이터들을 HTML태그로 변환시키기

function addCoffeeList(obj, gallery) {
    let nameIndex = exportName(obj);
    let imgIndex = exportUrl(obj);
    
    for (let i = 0; i < obj.length; i++) {
      
    }
};

addCoffeeList(coldBrewList, coldBrewGall);
addCoffeeList(brewedList, brewedGall);

함수 addCoffeeList은 파라미터로 객체 이름과 출력해낼 갤러리 이름을 받아낼겁니다.
마음만으로는 위쪽에서 반환된 coffeeNamecoffeeImg 변수를 그대로 가져오고 싶습니다. 그런데 저 변수들은 exportName 내에서만 활용이 가능한 변수라서 또 변수를 지정해뒀어요.

이제 변수 nameIndeximgIndex가 그 자리를 대신합니다.
그리고 객체의 데이터 개수만큼 for문이 작동할텐데, 저렇게 다중 구조의 HTML을 삽입하려면 어떻게 해야할까요? 그래서 찾아봤습니다.

function function1() {
  var ul = document.getElementById("list");
  var li = document.createElement("li");//변수 li는 <li>태그
  li.appendChild(document.createTextNode("Four"));//<li>태그 내에 'Four'이라는 텍스트 삽입, <li>Four</li>로 만들어짐
  ul.appendChild(li);//이런 li가 ul 하위에 추가됨
}

와~createElement로 태그를 하나하나 만들어준 다음 createTextNode로 데이터를 넣고appendChild를 쓰면 되는군요~

되겠냐고

<li>
    <a class="coffee-thumbnail" href="#">
       <div class="coffee-img"><img src="img/cb-01.jpg" alt="cb-01"/></div>
       <p class="coffee-name">커피이름</p>
    </a>
</li>

저는 li 밑에 a가 있고 또 그 안에 divp가 있는 복잡한걸 만들고... 거기에 클래스랑 url까지 줄거라니까요?
일단 더이상 생각하기 싫어서, 변수 자체를 이렇게 만들어 줍니다.

function addCoffeeList(obj, gallery) {
    let nameIndex = exportName(obj);
    let imgIndex = exportUrl(obj);
    
    for (let i = 0; i < obj.length; i++) {
        let listTag = `<li><a class="coffee-thumbnail" href="#">
        <div class="coffee-img">
        <img src="${imgIndex[i]}" alt="${imgIndex[i].substr(4,imgIndex[i].length)}"/>
        </div><p class="coffee-name">${nameIndex[i]}</p></a></li>`      
    }
};

src에는 i번째 데이터의 이미지 경로가 들어갈테고, alt값에는 이미지 경로에서 /img/만 제외한 cb-01.jpg형식의 텍스트가 들어갈 예정입니다.
.coffee-name안에는 i번째nameIndex인 이름값이 들어가고..
하지만 이러한 태그를 아무리 HTML에 넣으려 해봤자,

appendChild(listTag) : 실패
append(listTag) : 실패

어쩌라는 걸까요? 슬퍼진 저는 이렇게 생성된 li태그를 배열에 담아둔 후 무작정 태그들을 집어넣기로 했습니다.

 function addCoffeeList(obj, gallery) {
    let nameIndex = exportName(obj);
    let imgIndex = exportUrl(obj);
    let tagArray = [];
   
    for (let i = 0; i < obj.length; i++) {
        let listTag = `<li><a class="coffee-thumbnail" href="#">
        <div class="coffee-img">
        <img src="${imgIndex[i]}" alt="${imgIndex[i].substr(4,imgIndex[i].length)}"/>
        </div><p class="coffee-name">${nameIndex[i]}</p></a></li>`
        
        tagArray.push(listTag);
    }
};

이제 배열 tagArray에 담긴 열 몇개의 li들을 다시 뽑아내어 html에 삽입해야 합니다.

생성된 수많은 li 태그들을 ul 안에 넣어주기

문제
gallery.innerHTML = tagArray;
이런 식으로 tagArray 안의 태그들을 그대로 넣었다가는,
배열 내의 쉼표까지 전부 화면에 나타납니다.
그래서 쉼표들을 전부 제거해줘야 했습니다.

해결
검색해보니 join()이라는 메소드가 있더라고요.( join에 대하여 )
배열의 모든 요소를 연결해 하나의 문자열로 만들어주는 메소드입니다.

function addCoffeeList(obj, gallery) {
    let nameIndex = exportName(obj);
    let imgIndex = exportUrl(obj);
    let tagArray = [];
    for (let i = 0; i < obj.length; i++) {
        let listTag = `<li><a class="coffee-thumbnail" href="#">
        <div class="coffee-img">
        <img src="${imgIndex[i]}" alt="${imgIndex[i].substr(4,imgIndex[i].length)}"/>
        </div><p class="coffee-name">${nameIndex[i]}</p></a></li>`
        tagArray.push(listTag);
    }
    
    let tagToString = tagArray.join('');
    gallery.innerHTML = tagToString;

};

곧장 실행해봤더니, 이 방법으로 성공!
이제 객체에 데이터 몇개만 추가해주면 리스트가 저절로 만들어지네요!

3. 완료된 자바스크립트 코드

//coffee-gall 리스트 추가
const coldBrewList = [{
    name: '나이트로 바닐라 크림',
    imgUrl: 'img/cb-01.jpg'
}, {
    name: '나이트로 콜드 브루',
    imgUrl: 'img/cb-02.jpg'
}, {
    name: '돌체 콜드 브루',
    imgUrl: 'img/cb-03.jpg'
}, {
    name: '바닐라 크림 콜드 브루',
    imgUrl: 'img/cb-04.jpg'
}, {
    name: '벨벳 다크 모카 나이트로',
    imgUrl: 'img/cb-05.jpg'
}, {
    name: '시그니처 더 블랙 콜드 브루',
    imgUrl: 'img/cb-06.jpg'
}, {
    name: '제주 비자림 콜드 브루',
    imgUrl: 'img/cb-07.jpg'
}, {
    name: '콜드 브루',
    imgUrl: 'img/cb-08.jpg'
}, {
    name: '콜드 브루 몰트',
    imgUrl: 'img/cb-09.jpg'
}, {
    name: '콜드 브루 오트 라떼',
    imgUrl: 'img/cb-10.jpg'
}]

const brewedList = [{
    name: '아이스 커피',
    imgUrl: 'img/b-01.jpg'
}, {
    name: '오늘의 커피',
    imgUrl: 'img/b-02.jpg'
}]

//변수 선언
const coldBrewGall = document.querySelector('.cold-brew .coffee-gall'),
    brewedGall = document.querySelector('.brewed .coffee-gall');

//함수 선언
function exportName(data) {
    let coffeeName = [];
    for (let key in data) {
        coffeeName.push(data[key]['name']);
       
    }
    return coffeeName;
}

function exportUrl(data) {
    let coffeeImg = [];
    for (let key in data) {
        coffeeImg.push(data[key]['imgUrl']);
    }
    return coffeeImg;
}

function addCoffeeList(obj, gallery) {
    let nameIndex = exportName(obj);
    let imgIndex = exportUrl(obj);
    let tagArray = [];
    for (let i = 0; i < obj.length; i++) {
        let listTag = `<li><a class="coffee-thumbnail" href="#">
        <div class="coffee-img">
        <img src="${imgIndex[i]}" alt="${imgIndex[i].substr(4,imgIndex[i].length)}"/>
        </div><p class="coffee-name">${nameIndex[i]}</p></a></li>`
        tagArray.push(listTag);
    }
    
    let tagToString = tagArray.join('');
    gallery.innerHTML = tagToString;

};

addCoffeeList(coldBrewList, coldBrewGall);
addCoffeeList(brewedList, brewedGall);

로그인 페이지의 버튼 새로고침 현상 때처럼 스트레스를 받지는 않았지만, 만족할만한 검색 결과가 계속 나오지 않아 꽤 애를 먹었습니다.
그래도 예전 디자이너 시절때 하나하나 html코드로 갤러리를 짰을 때에 비하면 굉장히 많은 발전을 이루었다고 생각해서 뿌듯해집니다.

profile
진짜 간단하게 작성한 TIL 블로그

1개의 댓글

comment-user-thumbnail
2024년 9월 23일

잘 봤어요 :)

답글 달기