[Portfolio] Naver Shopping Live

jwww·2023년 4월 12일
0

포트폴리오

목록 보기
6/6

네이버 쇼핑라이브는 fetch 함수를 통한 비동기 통신을 중심으로 작업하였습니다.

🔎프로젝트 정보

  • 프로젝트명: 네이버 쇼핑라이브
  • 제작기간: 3일
  • 분류: 적응헝 MOBILE

🚩포인트

  1. 비동기 통신
    1-0. fetch() 기본
    1-1. fetch 함수로 json 데이터 받아오기
    1-2. 탭메뉴에 따라 데이터 받아오기

  2. 현재 시간 구하기

  3. 제이쿼리 자바스크립트로 수정
    3-1. 토글 버튼 클릭 이벤트
    3-2. 탭메뉴 클릭 이벤트



1. 비동기 통신


1-0. fetch() 기본

리소스를 비동기적으로 가져올 수 있는 fetch 함수를 사용해 필요한 데이터를 호출하여 만들었습니다.

(1) json에 콘텐츠로 들어갈 데이터의 이름과 값을 입력합니다.

{
    "items":[
        {
            "id":"0",
            "snippet":{
                "title":"가성비 대박 전북투어패스",
                "view":"12,103",
            }
        },
     ...
 }

(2) 스크립트에서 fetch() 함수에 json 파일 경로를 입력하고 요청 결과가 성공적이면 then() 을 실행합니다.
html 변수에 화면에 보여질 레이아웃 html 코드를 담고 변경되어야할 부분만 json 데이터를 나타냅니다.

fetch('./assets/data/trendItemData.json')
    .then((response) => response.json())
    .then((json) => {
        data = json.items;
        let html = '';
        data.forEach(element => {
            html += `<li class="list-item">
                       <p>${element.snippet.title}</p>
                       <span class="count">${element.snippet.view}</span>
                    </li>`
        });
        document.getElementById('popularList').innerHTML = html;
    })

1-1. 화제의 라이브 속으로

라이브 리스트를 클릭하면 라이브 메인이 해당 내용으로 변경됩니다.

라이브 리스트 fetch 함수에서 <a href="${element.id}"> a태그 href 속성 값에 json 데이터의 id 값을 받아옵니다.

라이브 메인은 라이브 리스트가 클릭됨에 따라 해당하는 이미지와 내용을 보여줘야하므로 함수로 만들어서 리스트가 클릭 되었을 때 실행해줍니다. ( 초기실행은 liveMain(0)으로 )

result 변수에 filter() 메서드를 통해 json 데이터의 id 값과 number 매개변수가 일치하는 값을 가져옵니다.

( 이 때 number 매개변수는 라이브 리스트의 앵커 태그 링크 값 )

// 라이브 리스트
fetch('./assets/data/shoppingLiveData.json')
    .then((response) => response.json())
    .then((json) => {
        data = json.items;
        let html = '';
        data.forEach(element => {
            html += `<li class="live-item" role="tab" aria-selected="${element.snippet.selected}">
                        <a href="${element.id}" class="live">
                            <svg width="85" height="98" viewBox="0 0 85 98" focusable="false" aria-hidden="true"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.998 0a8 8 0 0 0-8 8v35.08L1.38 47.713a1 1 0 0 0 0 1.572l5.618 4.635V90a8 8 0 0 0 8 8h61.999a8 8 0 0 0 8-8v-1.78C85 88.148 85 88.075 85 88V78h-.002V8a8 8 0 0 0-8-8h-62Zm67 78h-72V8a5 5 0 0 1 5-5h62a5 5 0 0 1 5 5v70Z" fill="#6563F0"></path></svg>
                            <div class="img-box">
                                <img src="${element.snippet.thumbnail.side}" alt="${element.snippet.title}">
                            </div>
                            <div class="text-box">
                                <em>${element.snippet.thumbnail.time}</em>
                            </div>
                        </a>
                    </li>`
      });
      document.getElementById('liveList1').innerHTML = html;
})
function liveMain(number) {
      fetch('./assets/data/shoppingLiveData.json')
      .then((response) => response.json())
      .then((json) => {
          data = json.items;
          let result = data.filter(function (parm) {return parm.id == number});
          let html = '';
          result.forEach(element => {
              html += `<div role="tabpanel" class="content" aria-selected="true">
                          <div class="time-box"><strong>${element.snippet.time}</strong></div>
                          <div class="img-box">
                              <img src="${element.snippet.thumbnail.normal}">
                          </div>
                          <div class="text-box">
                              <div class="info-area">
                                  <strong class="title">${element.snippet.title}</strong>
                                  <em class="news">${element.snippet.wait}명이 기다리는 중</em>
                              </div>
                              <div class="alarm-area">
                                  <a href="" class="link-alarm">
                                      <svg width="14" height="14" viewBox="0 0 15 15" xmlns="https://www.w3.org/2000/svg" focusable="false" aria-hidden="true">...</svg>
                                  </a>
                              </div>
                            </div>
                      </div>`
          });
          document.getElementById('liveMain1').innerHTML = html;
      })
}
liveMain(0);
/**
 * 아이템을 클릭했을 때 해당 아이템을 가져옴
 * - aria-selected 속성으로 스타일 변경.
 * @aHref : live 속성의 href 값을 가져와 liveMain의 인자로 넣고 함수를 실행시킨다.
 */
liveList.addEventListener('click', (e) => {
    e.preventDefault();

    const live = e.target.closest('.live');
    const liveList = document.querySelectorAll('.live-item');
    
    if (!live) { return; }
    const aHref = live.getAttribute('href');

    liveList.forEach(item => { item.setAttribute('aria-selected','false'); })
    live.parentElement.setAttribute('aria-selected','true');
    
    liveMain(aHref);
})

1-2. 탭메뉴에 따라 데이터 받아오기

html에 각 메뉴마다 data-sort 속성을 지정해두고 숫자 값을 넣어준 뒤, (전체는 all, 뷰티는 1, 푸드는 2 등)
메뉴를 클릭했을 때 sort 값을 받아와 값을 매개변수로 fetch 함수를 담은 함수를 호출하고
trendLive의 매개변수 sort의 값이 all이라면 data 전체를, 아니라면 매개변수 sort와 json의 sort가 일치하는 데이터를 구분하여 선택한 메뉴의 리스트만 나올 수 있도록 합니다.

  • fetch 함수
function trendLive(sort){
      fetch('./assets/data/trendItemData.json')
      .then((response) => response.json())
      .then((json) => {
          data = json.items;
          result = (sort === 'all') ? data : data.filter(function (parm) {return parm.sort == sort})

          let html = '';
          let rank = 1;
          result.forEach(element => {
                if ( rank > 10 ) { return false; }
                html += `...`
                        rank++;
          });
          document.getElementById('trendLive').innerHTML = html;
   })
}
trendLive('all');
  • 메뉴를 클릭했을 때 이벤트
 function tabMenuClick(menu) {
        for ( let i = 0; i < menu.length; i++ ) {
            menu[i].addEventListener('click', function(e){
                e.preventDefault();
    
                let sort = this.dataset.sort;
                let livesort = this.parentNode.parentNode.dataset.livesort;
        
                for ( let j = 0; j < menu.length; j++ ) { 
                    menu[j].setAttribute('aria-selected','false'); 
                }
                this.setAttribute('aria-selected','true');

                if ( livesort == 1 ) {
                    typeLive(sort);
                } else if ( livesort == 2 ) {
                    trendLive(sort);
                }
            })
        }
    }
const trendTabMenu = document.querySelectorAll('.section.trend .menu-item .menu');

tabMenuClick(trendTabMenu);

2. 현재 시간 구하기


자바스크립트에서는 Date 객체를 통해 현재 시간을 가져올 수 있습니다.
Date 객체가 가지고 있는 getMonth(), getDate(), getHours(), getMinutes() 메서드로 월, 일, 시, 분 값을 얻어와 현재 시간을 표시합니다.

setInterval(()=>{ currentTime(); },60000)
일정 시간 간격을 두고 반복 실행해주는 setInterval() 함수를 이용해 1분마다 한 번 씩 시간을 갱신합니다.

function currentTime() {
        const current = new Date();
        let currentMonth = current.getMonth()+1;
        let currentDay = current.getDate();
        let currentHour = current.getHours();
        let localHour = currentHour > 12 ? currentHour - 12 : currentHour;
        let currentMin = current.getMinutes();

        if ( currentHour <= 12 ) {
            time = `${currentMonth}${currentDay}일 오전 ${localHour}${currentMin}분 기준`;
        } else {
            time = `${currentMonth}${currentDay}일 오후 ${localHour}${currentMin}분 기준`;
        }

        html = `<span class="time">${time}</span>`;
        $('.section.popular .time').html(html);
}
currentTime();

 setInterval(()=>{
        currentTime();
},60000)

3. 제이쿼리 자바스크립트로 수정


처음 작업 시, 제이쿼리로 작업을 했으나 자바스크립트로 수정했습니다.

3-1. 토글 버튼 클릭 이벤트

버튼을 클릭했을 때 가상클래스 on이 추가/제거 되는 함수를 만들어 각 버튼 요소들을 매개변수로 받아 처리했습니다.

  • 기존 ( 제이쿼리 )
// 시청순 / 구매순 분류버튼
$('.select-area').click(function(){
    $(this).toggleClass('on');
})

// footer 정보 더보기 버튼
$('.footer .btn-info').click(function(){
    $(this).toggleClass('on');
    $('.footer .btn-wrap').toggleClass('on');
})
  • 수정 후 ( 자바스크립트 )
function toggleBtnClick(btn) {
    btn.forEach(element => {
        element.addEventListener('click', (e)=>{
            const button = e.target.closest('#toggle');
            
            button.parentElement.classList.toggle('on');
        })
    });
}
const sortBtn = document.querySelectorAll('.select-area .btn-sort');
const infoBtn = document.querySelectorAll('.footer .btn-info');

toggleBtnClick(sortBtn);
toggleBtnClick(infoBtn);

3-2. 탭메뉴 클릭 이벤트

탭메뉴를 클릭했을 때 동일한 이벤트가 발생하기 때문에 하나의 함수로 만들어 처리했습니다.

menu의 부모인 menuList에 이벤트를 걸어 이벤트 위임하는 방식을 사용했습니다.

이 때 탭메뉴의 부모를 클릭하면 menu가 존재하지 않아 에러가 발생하는 문제를 해결하기 위해 if문으로 menu가 없으면 그냥 return 되도록 처리해주었습니다.

버튼을 클릭했을 때 typeLive, trendLive 함수가 호출되는지 구분이 필요하기 때문에 menu(<a>)의 조상인 <ul>data-livesort 속성을 넣고 변수 livesort로 받아 어떤 탭메뉴인지 구분했습니다.

  • 기존 ( 제이쿼리 )
$('.section.type .menu-item .menu').click(function(e){
        e.preventDefault();
        let sort = $(this).data('sort');
        $('.section.type .menu-item .menu').attr('aria-selected','false');
        $(this).attr('aria-selected','true');
        typeLive(sort);
 })

$('.section.trend .menu-item .menu').click(function(e){
         e.preventDefault();
         let sort = $(this).data('sort');
         $('.section.trend .menu-item .menu').attr('aria-selected','false');
         $(this).attr('aria-selected','true');
         trendLive(sort);
})
  • 수정 후 ( 자바스크립트 )
function tabMenuClick(menuList) {
    menuList.addEventListener('click', (e) => {
        e.preventDefault();

        let menu = e.target.closest('.menu');
        if (!menu) { return; }
        let sort =  menu.dataset.sort;
        let livesort = e.currentTarget.dataset.livesort;
        
        e.currentTarget.querySelectorAll('.menu').forEach(item => {
            item.setAttribute('aria-selected','false');
        })
        menu.setAttribute('aria-selected','true');

        livesort === 'typeLive' ? typeLive(sort) : trendLive(sort);
    })
}

const typeTabMenu = document.querySelector('.section.type .menu-list');
const trendTabMenu = document.querySelector('.section.trend .menu-list');

tabMenuClick(typeTabMenu);
tabMenuClick(trendTabMenu);
profile
퍼블리셔 공부 블로그 입니다

0개의 댓글