본문 바로가기

Javascript

Javascript & TypeScript Essential - 패스트캠퍼스 챌린지 10일차

#패스트캠퍼스_환급_챌린지 https://bit.ly/3FVdhDa #10일차

 

복잡한 UI 구현을 위한 준비 작업 - 템플릿

코드를 명확하게 하기 위해 newsFeed의 출력방식을 template로 HTML 구조를 문자열로 담고 이를 replace하는 방식으로 변경해 보자.

 

1. template 변수를 만들고 HTML 구조를 문자열로 담는다. 반복적인 출력을 위한 뉴스 목록은 {{__news_feed__}} 라는 임의의 문자열로 만들고, 이전페이지번호와 다음페이지번호는 각각 {{__prev_page__}}와 {{__next_page__}}로 정한다.

function newsFeed () {
  
  const newsFeed = getData(NEWS_URL);
  const newsList = [];

  let template = `
    <div>
      <h1>Kacker News</h1>
      <ul>
        {{__news_feed__}}
      </ul>
      <div>
        <a href="#/page/{{__prev_page__}}">이전 페이지</a>
        <a href="#/page/{{__next_page__}}">다음 페이지</a>
      </div>
    </div>
  `

  newsList.push('<ul>');
  for (let i = ((store.currentPage - 1) * 10); i < store.currentPage * 10; i++) {
    newsList.push(`
      <li>
        <a href="#/show/${ newsFeed[i].id }">
        ${ newsFeed[i].title } (${ newsFeed[i].comments_count })
        </a>
      </li>
    `);
  }
  newsList.push('</ul>');
  newsList.push(`
    <div>
      <a href="#">이전 페이지</a>
      <a href="#">다음 페이지</a>
    </div>
  `)
  newsList.push(`
    <div>
      <a href="#/page/${ store.currentPage > 1 ? store.currentPage - 1 : 1 }">이전 페이지</a>
      <a href="#/page/${ store.currentPage < newsFeed.length / 10 ? store.currentPage + 1 : newsFeed.length / 10 }">다음 페이지</a>
    </div>
  `);

  container.innerHTML = newsList.join('');
}

2.  반복적인 뉴스 목록은 기존과 동일하게 사용한 후 하나의 문자열로 합쳐서 {{__news_feed__}}와 replace한다.

function newsFeed () {
  
  const newsFeed = getData(NEWS_URL);
  const newsList = [];

  let template = `
    <div>
      <h1>Kacker News</h1>
      <ul>
        {{__news_feed__}}
      </ul>
      <div>
        <a href="#/page/{{__prev_page__}}">이전 페이지</a>
        <a href="#/page/{{__next_page__}}">다음 페이지</a>
      </div>
    </div>
  `;

  //newsList.push('<ul>');
  for (let i = ((store.currentPage - 1) * 10); i < store.currentPage * 10; i++) {
    newsList.push(`
      <li>
        <a href="#/show/${ newsFeed[i].id }">
        ${ newsFeed[i].title } (${ newsFeed[i].comments_count })
        </a>
      </li>
    `);
  }
  //newsList.push('</ul>');
  template = template.replace('{{__news_feed__}}', newsList.join(''));

  newsList.push(`
    <div>
      <a href="#">이전 페이지</a>
      <a href="#">다음 페이지</a>
    </div>
  `)
  newsList.push(`
    <div>
      <a href="#/page/${ store.currentPage > 1 ? store.currentPage - 1 : 1 }">이전 페이지</a>
      <a href="#/page/${ store.currentPage < newsFeed.length / 10 ? store.currentPage + 1 : newsFeed.length / 10 }">다음 페이지</a>
    </div>
  `);

  container.innerHTML = newsList.join('');
}

3. 이전페이지와 다음페이지 번호도 각각 replace한 후 template를 container에 넣어서 출력한다.

function newsFeed () {
  
  const newsFeed = getData(NEWS_URL);
  const newsList = [];

  let template = `
    <div>
      <h1>Kacker News</h1>
      <ul>
        {{__news_feed__}}
      </ul>
      <div>
        <a href="#/page/{{__prev_page__}}">이전 페이지</a>
        <a href="#/page/{{__next_page__}}">다음 페이지</a>
      </div>
    </div>
  `;

  //newsList.push('<ul>');
  for (let i = ((store.currentPage - 1) * 10); i < store.currentPage * 10; i++) {
    newsList.push(`
      <li>
        <a href="#/show/${ newsFeed[i].id }">
        ${ newsFeed[i].title } (${ newsFeed[i].comments_count })
        </a>
      </li>
    `);
  }
  //newsList.push('</ul>');
  template = template.replace('{{__news_feed__}}', newsList.join(''));

  // newsList.push(`
  //   <div>
  //     <a href="#">이전 페이지</a>
  //     <a href="#">다음 페이지</a>
  //   </div>
  // `)
  // newsList.push(`
  //   <div>
  //     <a href="#/page/${ store.currentPage > 1 ? store.currentPage - 1 : 1 }">이전 페이지</a>
  //     <a href="#/page/${ store.currentPage < newsFeed.length / 10 ? store.currentPage + 1 : newsFeed.length / 10 }">다음 페이지</a>
  //   </div>
  // `);
  template = template.replace('{{__prev_page__}}', store.currentPage > 1 ? store.currentPage - 1 : 1);
  template = template.replace('{{__next_page__}}', store.currentPage < newsFeed.length / 10 ? store.currentPage + 1 : newsFeed.length / 10)

  //container.innerHTML = newsList.join('');
  container.innerHTML = template
}

UI로 사용할 tailwindcss 사용 준비

tailwindcss 사이트(https://tailwindcss.com/)에서 Get started를 클릭하여 사용방법을 확인하자

tailwindcss 사이트 get startd 클릭

1. installation 페이지 아래 CDN을 사용하는 방법을 이용해서 index.html에 <link>를 추가한다.

<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
<!-- index.html -->
<!doctype html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<title>HN client</title>
	<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
	<noscript>
		You need to enable JavaScript to run this app.
	</noscript>
  <div id="root">
  </div>
  <script src="app.js" type="module"></script>
</body>
</html>

2. tailwindcss제공하는  class를 사용하여 간단하게 margin과 padding을 줘보자.

  let template = `
    <div class="container mx-auto p-4">
      <h1>Kacker News</h1>
      <ul>
        {{__news_feed__}}
      </ul>
      <div>
        <a href="#/page/{{__prev_page__}}">이전 페이지</a>
        <a href="#/page/{{__next_page__}}">다음 페이지</a>
      </div>
    </div>
  `;

이번시간까지 작성한 전체 소스이다.

const container = document.getElementById('root');
const ajax = new XMLHttpRequest();
const content = document.createElement('div');
const NEWS_URL ='https://api.hnpwa.com/v0/news/1.json';
const CONTENT_URL = 'https://api.hnpwa.com/v0/item/@id.json';

//공유되는 값
const store = {
  currentPage: 1
}

function getData (url) {
  ajax.open('GET', url, false);
  ajax.send();

  return JSON.parse(ajax.response);
}

function newsFeed () {
  
  const newsFeed = getData(NEWS_URL);
  const newsList = [];

  let template = `
    <div class="container mx-auto p-4">
      <h1>Kacker News</h1>
      <ul>
        {{__news_feed__}}
      </ul>
      <div>
        <a href="#/page/{{__prev_page__}}">이전 페이지</a>
        <a href="#/page/{{__next_page__}}">다음 페이지</a>
      </div>
    </div>
  `;

  for (let i = ((store.currentPage - 1) * 10); i < store.currentPage * 10; i++) {
    newsList.push(`
      <li>
        <a href="#/show/${ newsFeed[i].id }">
        ${ newsFeed[i].title } (${ newsFeed[i].comments_count })
        </a>
      </li>
    `);
  }
  template = template.replace('{{__news_feed__}}', newsList.join(''));

  template = template.replace('{{__prev_page__}}', store.currentPage > 1 ? store.currentPage - 1 : 1);
  template = template.replace('{{__next_page__}}', store.currentPage < newsFeed.length / 10 ? store.currentPage + 1 : newsFeed.length / 10)

  container.innerHTML = template
}


function newsDetail () {
  const id = location.hash.substr(7);

  const newsContent = getData(CONTENT_URL.replace('@id', id));

  container.innerHTML = `
    <h1>${ newsContent.title }</h1>
    <div>
      <a href="#/page/${ store.currentPage }">목록으로</a>
    </div>
  `;

}

function router() {
  const routerPath  = location.hash;
  if (routerPath === '') {
    newsFeed();
  }
  else if (routerPath.indexOf('#/page/') >= 0) {
    store.currentPage = Number(routerPath.substr(7));
    newsFeed();
  } else {
    newsDetail();
  }
}


window.addEventListener('hashchange', router);

router();

ch03_07.복잡한 UI 구현을 위한 준비 작업 - 템플릿