네이버 쇼핑라이브는 fetch 함수를 통한 비동기 통신을 중심으로 작업하였습니다.
비동기 통신
1-0. fetch() 기본
1-1. fetch 함수로 json 데이터 받아오기
1-2. 탭메뉴에 따라 데이터 받아오기
현재 시간 구하기
제이쿼리 자바스크립트로 수정
3-1. 토글 버튼 클릭 이벤트
3-2. 탭메뉴 클릭 이벤트
리소스를 비동기적으로 가져올 수 있는 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;
})
라이브 리스트를 클릭하면 라이브 메인이 해당 내용으로 변경됩니다.
라이브 리스트 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);
})
html에 각 메뉴마다 data-sort 속성을 지정해두고 숫자 값을 넣어준 뒤, (전체는 all, 뷰티는 1, 푸드는 2 등)
메뉴를 클릭했을 때 sort 값을 받아와 값을 매개변수로 fetch 함수를 담은 함수를 호출하고
trendLive의 매개변수 sort의 값이 all이라면 data 전체를, 아니라면 매개변수 sort와 json의 sort가 일치하는 데이터를 구분하여 선택한 메뉴의 리스트만 나올 수 있도록 합니다.
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);
자바스크립트에서는 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)
처음 작업 시, 제이쿼리로 작업을 했으나 자바스크립트로 수정했습니다.
버튼을 클릭했을 때 가상클래스 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);
탭메뉴를 클릭했을 때 동일한 이벤트가 발생하기 때문에 하나의 함수로 만들어 처리했습니다.
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);