타입스크립트를 위한 환경설정

 

자바스크립트로 만들어진 해커뉴스 페이지를 타입스크립트로 변환하는 작업을 할 것인데 이런 작업을 포팅이라고 한다.

 

기존에 해커뉴스 페이지는 html파일(index.html)과 js파일(app.js)로 구성되어 있는데 타입스크립트를 사용하기 위해 app.js파일을 app.ts파일로 변환한다. 그리고 tsconfig.json이라는 파일을 생성한다.

 

- tsconfig.json

{
    "compilerOptions": { // 주로 사용하는 부분
        "strict": true, // 타입체크
        "target": "ES5", // 변환할버전
        "module": "commonJS", 
        "alwaysStrict": true,
        "noImplicitAny": true,
        "noImplicitThis": true,
        "sourceMap": true, // html과 js, ts 파일 등을 map 형식으로 나타낸다
        "downlevelIteration": true
    }
}

html은 타입스크립트 파일 자체를 읽어낼 수 없기 때문에 내부적으로 타입스크립트를 자바스크립트로 변환하는 작업이 필요하다. 여기서 config 파일이 그 작업을 도와주고 또 다른 세부 설정도 할 수 있다. parcel 번들러를 실행하고 나면 작업 폴더 내 dist폴더 안에 또 다른 html파일과 js파일이 있는데 형식이 조금 다른 파일이 생성된다. (트랜스파일링이 된 것)

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

상태를 가져보자. 읽은 글 표시하기

 

현재 해커뉴스 페이지에 열람한 글의 상태를 체크해주는 로직이 없기 때문에 해당 로직을 만들것이다.

 

1) 글의 고유 id를 통해 읽음 처리를 하는 데이터 구조를 만든다.

2) 네트워크를 통해 newsFeed를 가져온 데이터에 새로운 속성을 추가한다.

 

const container = document.querySelector('#root');
const ajax = new XMLHttpRequest();
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,
    feeds: [],
}

function getData(url){    
	...
}

function makeFeeds(feeds){
    for(let i=0; i<feeds.length; i++){
        feeds[i].read = false;
    }
    return feeds;
}

function newsFeed(){
    let newsFeed = store.feeds;
    const newsTotalPage = newsFeed.length / 10;
    const newsList = [];
    let template = `
    ...
    `;

    if(newsFeed.length === 0){
        newsFeed = store.feeds = makeFeeds(getData(NEWS_URL));
    }
    
    for(let i=(store.currentPage - 1) * 10; i<store.currentPage * 10; i++){
        newsList.push(`
            <div class="p-6 ${newsFeed[i].read ? 'bg-red-500' : 'bg-white'} mt-6 rounded-lg shadow-md transition-colors duration-500 hover:bg-green-100">
                <div class="flex">
                    <div class="flex-auto">
                        <a href="#/show/${newsFeed[i].id}">${newsFeed[i].title}</a>  
                    </div>
                    <div class="text-center text-sm">
                        <div class="w-10 text-white bg-green-300 rounded-lg px-0 py-2">${newsFeed[i].comments_count}</div>
                    </div>
                </div>
                <div class="flex mt-3">
                    <div class="grid grid-cols-3 text-sm text-gray-500">
                        <div><i class="fas fa-user mr-1"></i>${newsFeed[i].user}</div>
                        <div><i class="fas fa-heart mr-1"></i>${newsFeed[i].points}</div>
                        <div><i class="far fa-clock mr-1"></i>${newsFeed[i].time_ago}</div>
                    </div>  
                </div>
            </div>
        `);
    }

    template = template.replace('{{__news_feed__}}', newsList.join(''));
    template = template.replace('{{__prev_page__}}', `${store.currentPage > 1 ? store.currentPage - 1 : 1}" ${store.currentPage === 1 ? 'style="pointer-events: none;"' : " "}`);
    template = template.replace('{{__next_page__}}', `${store.currentPage + 1}" ${store.currentPage === newsTotalPage ? 'style="pointer-events: none;"' : " "}`);    

    container.innerHTML = template;
}

function newsDetail(){
    const id = location.hash.substring(7);
    const newsContent = getData(CONTENT_URL.replace('@id', id));
    let template = `
        ...
    `;

    for(let i=0; i<store.feeds.length; i++){
        if(store.feeds[i].id === parseInt(id)){
            store.feeds[i].read = true;
            break;
        }
    }

    function makeComment(comments, called = 0){
        const commentString = [];
                
        for(let i=0; i<comments.length; i++){
            commentString.push(`
                <div style="padding-left: ${called * 40}px;" class="mt-4">
                    <div class="text-gray-400">
                        <i class="fa fa-sort-up mr-2"></i>
                        <strong>${comments[i].user}</strong> ${comments[i].time_ago}
                    </div>
                    <p class="text-gray-700">${comments[i].content}</p>
                </div>
            `);

            if(comments[i].comments.length > 0){
                commentString.push(makeComment(comments[i].comments, called + 1)); // 재귀 호출
            }
        }

        return commentString.join('');
    }

    container.innerHTML = template.replace('{{__comments__}}', makeComment(newsContent.comments));
}

function router(){
	...
}

window.addEventListener('hashchange', router);

router();

 

먼저 기존 newsFeed는 getData()를 통해 newsFeed를 호출 할 때마다 ajax로 데이터를 불러 들였기 때문에 공공으로 사용하는 store객체에 feeds라는 배열을 추가하여 store의 안에 있는 feeds 배열로 사용한다. ajax로 불러온 데이터를 store에 저장했기 때문에 전역적으로 데이터를 관리할 수 있으며 데이터의 API 형태나 필요한 데이터 구조를 추가할 수 있다. 데이터 읽음 처리를 위해 makeFeed() 함수를 통해 read라는 boolean값 데이터를 추가하여 글을 조회하지 않았을 시엔 false, 조회 하였을 땐 true 값으로 구분한다.

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

tailwindCss를 통한 UI 수정

 

지금까지 만들어진 해커뉴스의 디자인적인 부분은 tailwindCss를 가지고 작업을 할것이다. 그렇게 하기 전에 기존에 있는 해커뉴스의 코드는 template을 가지고 구조적인 부분을 수정했지만 아직도 문제가 있다.

 

template의 <ul>, <li> 태그들은 아직도 반복문을 따로 사용해서 작업하는 부분이나 template의 동적인 데이터를 추가해야 하는 부분은 데이터의 변경이 있을때마다 replace함수를 써 줘야하기 때문에 여러가지 기능들이 추가되면 replace 함수를 그만큼 추가로 사용해야 하는 문제점이 있다. 따라서 템플릿엔진(ejs, pug, nunjucks, handlebars 등)을 사용할 것이다.

 

그 전에 먼저 UI 작업을 먼저 한다.

 

https://fontawesome.com/

 

Font Awesome

The world’s most popular and easiest to use icon set just got an upgrade. More icons. More styles. More Options.

fontawesome.com

폰트와 아이콘을 가볍게 사용할 수 있다. (대부분 아이콘을 사용)

 

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"  integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA==" crossorigin="anonymous" referrerpolicy="no-referrer" />

마찬가지로 cdn.js 홈페이지에서 cdn으로 가져온다.

 

const container = document.querySelector('#root');
const ajax = new XMLHttpRequest();
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){    
   ...
}

function newsFeed(){
    const newsFeed = getData(NEWS_URL);
    const newsTotalPage = newsFeed.length / 10;
    const newsList = [];
    let template = `
    <div class="bg-gray-600 min-h-screen">
      <div class="bg-white text-xl">
        <div class="mx-auto px-4">
          <div class="flex justify-between items-center py-6">
            <div class="flex justify-start">
              <h1 class="font-extrabold">Hacker News</h1>
            </div>
            <div class="items-center justify-end">
              <a href="#/page/{{__prev_page__}}" class="text-gray-500">
                Previous
              </a>
              <a href="#/page/{{__next_page__}}" class="text-gray-500 ml-4">
                Next
              </a>
            </div>
          </div> 
        </div>
      </div>
      <div class="p-4 text-2xl text-gray-700">
        {{__news_feed__}}        
      </div>
    </div>
    `;
    
    for(let i=(store.currentPage - 1) * 10; i<store.currentPage * 10; i++){
        newsList.push(`
            <div class="p-6 ${newsFeed[i].read ? 'bg-red-500' : 'bg-white'} mt-6 rounded-lg shadow-md transition-colors duration-500 hover:bg-green-100">
                <div class="flex">
                    <div class="flex-auto">
                        <a href="#/show/${newsFeed[i].id}">${newsFeed[i].title}</a>  
                    </div>
                    <div class="text-center text-sm">
                        <div class="w-10 text-white bg-green-300 rounded-lg px-0 py-2">${newsFeed[i].comments_count}</div>
                    </div>
                </div>
                <div class="flex mt-3">
                    <div class="grid grid-cols-3 text-sm text-gray-500">
                        <div><i class="fas fa-user mr-1"></i>${newsFeed[i].user}</div>
                        <div><i class="fas fa-heart mr-1"></i>${newsFeed[i].points}</div>
                        <div><i class="far fa-clock mr-1"></i>${newsFeed[i].time_ago}</div>
                    </div>  
                </div>
            </div>
        `);
    }

    template = template.replace('{{__news_feed__}}', newsList.join(''));
    template = template.replace('{{__prev_page__}}', `${store.currentPage > 1 ? store.currentPage - 1 : 1}" ${store.currentPage === 1 ? 'style="pointer-events: none;"' : " "}`);
    template = template.replace('{{__next_page__}}', `${store.currentPage + 1}" ${store.currentPage === newsTotalPage ? 'style="pointer-events: none;"' : " "}`);    

    container.innerHTML = template;
}

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

    const newsContent = getData(CONTENT_URL.replace('@id', id));
    let template = `
        <div class="bg-gray-600 min-h-screen pb-8">
            <div class="bg-white text-xl">
                <div class="mx-auto px-4">
                    <div class="flex justify-between items-center py-6">
                        <div class="flex justify-start">
                            <h1 class="font-extrabold">Hacker News</h1>
                        </div>
                        <div class="items-center justify-end">
                            <a href="#/page/${store.currentPage}" class="text-gray-500">
                                <i class="fa fa-times"></i>
                            </a>
                        </div>
                    </div>
                </div>
            </div>

            <div class="border rounded-xl bg-white m-6 p-4 ">
                <h2>${newsContent.title}</h2>
                <div class="text-gray-400 h-20">
                    ${newsContent.content}
                </div>
                {{__comments__}}
            </div>
        </div>
    `;

    function makeComment(comments, called = 0){
        const commentString = [];
                
        for(let i=0; i<comments.length; i++){
            commentString.push(`
                <div style="padding-left: ${called * 40}px;" class="mt-4">
                    <div class="text-gray-400">
                        <i class="fa fa-sort-up mr-2"></i>
                        <strong>${comments[i].user}</strong> ${comments[i].time_ago}
                    </div>
                    <p class="text-gray-700">${comments[i].content}</p>
                </div>
            `);

            if(comments[i].comments.length > 0){
                commentString.push(makeComment(comments[i].comments, called + 1)); // 재귀 호출
            }
        }

        return commentString.join('');
    }

    container.innerHTML = template.replace('{{__comments__}}', makeComment(newsContent.comments));
}

function router(){
    ...
}

window.addEventListener('hashchange', router);

router();

(확연히 기존 template 변수에 사용된 html 태그보다 스타일링을 통해 내용이 길어짐)

 

각 목록 화면과 내용 화면에 UI 부분을 tailwindCss를 사용해서 디자인을 수정했다. html 태그의 클래스를 보게되면 css의 속성(display: flex -> flex, justify-content: space-between -> justify-between 등)을 tailwindCss만의 방식으로 클래스명을 사용하여 스타일링한 것을 알 수 있다.

 

해커뉴스의 내용엔 comment 데이터가 있는데 comment안에 comment가 있는 형식으로 단계가 정해져 있지 않은 구조이다. comment 부분은 makeComment() 함수를 통해 배열 안의 배열을 재귀 호출을 통해서 조회한다. comment배열 안의 comment가 있는지 조건문으로 처리하고 comment안의 배열이 없을 때 해당하는 값을 return 한다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

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

 

코드의 양과 복잡도는 비례하지 않는다. 코드의 양이 늘어날 수록 복잡도 또한 늘어나면 좋지 않은 구조의 코드라고 생각해야한다. 따라서 템플릿이라는 컨셉을 사용한다.

 

const container = document.querySelector('#root');
const ajax = new XMLHttpRequest();
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){    
    ...
}

function newsFeed(){
    const newsFeed = getData(NEWS_URL);
    const newsTotalPage = newsFeed.length / 10;
    const newsList = [];
    let template = `
        <div>
            <h1>Hacker 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}" ${store.currentPage === 1 ? 'style="pointer-events: none;"' : " "}`);
    template = template.replace('{{__next_page__}}', `${store.currentPage + 1}" ${store.currentPage === newsTotalPage ? 'style="pointer-events: none;"' : " "}`);    

    container.innerHTML = template;
}

function newsDetail(){
    ...
}

function router(){
    ...
}

window.addEventListener('hashchange', router);

router();

 

UI를 변경하기 전에 기존 DOM API를 사용했을 때보다 훨씬 더 보기 직관적이고 개발자도구의 Element와 구조가 비슷한 형태로 어느 부분에 어떤 데이터가 들어갈지 보다 잘 확인할 수 있는 구조가 되었다. 또한 변경이 필요한 부분이라면 어느 부분에서 변경이 일어나는지 한 눈으로 알 수있고 그것이 데이터이던지 화면을 구성하는 코드이던지 변경에 용이하다.

 

 

UI에 tailwind Css프레임워크 사용:

 

https://tailwindcss.com/

 

Tailwind CSS - Rapidly build modern websites without ever leaving your HTML.

Documentation for the Tailwind CSS framework.

tailwindcss.com

 

https://cdnjs.com/

 

cdnjs - The #1 free and open source CDN built to make life easier for developers

Simple. Fast. Reliable. Content delivery at its finest. cdnjs is a free and open-source CDN service trusted by over 12.5% of all websites, serving over 200 billion requests each month, powered by Cloudflare. We make it faster and easier to load library fil

cdnjs.com

cdnjs에서 tailwindCss 페이지의 cdn을 검색

 

<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">

cdn 적용

 

tailwind css는 CSS 프레임워크의 일종으로 부트스트랩과 비슷하지만 다소 차이가 있는것 같다. 사용법은 mt-1, ml-6 등 tailwind css 사이트에 있는 컴포넌트나 레이아웃 등을 참고하며 사용할 수 있다. 부트스트랩과 같은 다른 프레임워크들에 비해 기본 스타일 값을 사용하고 필요하다면 디테일하게 커스텀이 가능하다. 부트스트랩의 경우는 완성된 디자인의 컴포넌트를 갖다 쓰는 느낌이지만 tailwind css는 기본 스타일 값을 수정하고 수정하고 나서도 디자인의 일관성을 망치지 않을 수 있다. css-in-js 와는 컨셉이 확연히 다르다. 하지만 단점으로는 html 태그의 class가 하염없이 길어질 수도 있으며 css-in-js의 장점인 어떤 변수에따라 다른 값을 줄 수 있는 스타일링 등은 하기 힘들다.

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 14일차  (0) 2022.02.06
패스트캠퍼스 챌린지 13일차  (0) 2022.02.05
패스트캠퍼스 챌린지 11일차  (0) 2022.02.03
패스트캠퍼스 챌린지 10일차  (0) 2022.02.02
패스트캠퍼스 챌린지 9일차  (0) 2022.02.01

페이징 구현하기

 

const container = document.querySelector('#root');
const ajax = new XMLHttpRequest();
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); // method, Url, async
    ajax.send();

    return JSON.parse(ajax.response);
}

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

    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="#/page/${store.currentPage > 1 ? store.currentPage - 1 : 1}">이전 페이지</a>
            <a href="#/page/${store.currentPage + 1}">다음 페이지</a>
        </div>
    `)

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

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

    const newsContent = getData(CONTENT_URL.replace('@id', id));
    const title = document.createElement('h1');        

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

function router(){
    const routePath = location.hash;

    if(routePath === ''){
        newsFeed();        
    }else if(routePath.indexOf('#/page/') >= 0){
        store.currentPage = parseInt(routePath.substring(7));
        newsFeed();                
    }else{        
        newsDetail();
    }
}

window.addEventListener('hashchange', router);

router();

페이징 처리를 하기 위해서 전체적으로 공용으로 사용할 store라는 객체에 currentPage 값을 추가했다. 이 store 객체는 hacknews 페이지의 전역객체로 사용될 것이다. 리액트를 사용하면 상위 컴포넌트에서 하위 컴포넌트로 props를 통해 데이터를 전달하는데 리덕스를 사용하면 컴포넌트를 전역적으로 설정하고 다른 여러 컴포넌트에서 사용할 수 있다. 현재 만든 웹앱 구조의 store 객체의 컨셉은 리덕스처럼 사용될 것 같다. 지금은 단순 리터럴로 사용된 전역 객체지만 앞으로 약간의 변화를 통해 다른 객체들에서 전역적으로 작용할 객체가 될 것이다.

 

또한 페이징 처리를 할 url과 목록을 조회하는 url을 분리 시켰기 때문에 라우팅 처리를 해줘야하는 router 함수를 수정했다. hashchange 이벤트 리스너를 통해서 변화된 path에 따라 보여지는 화면이 newsFeed와 newsDetail로 나눠진다.

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 13일차  (0) 2022.02.05
패스트캠퍼스 챌린지 12일차  (0) 2022.02.04
패스트캠퍼스 챌린지 10일차  (0) 2022.02.02
패스트캠퍼스 챌린지 9일차  (0) 2022.02.01
패스트캠퍼스 챌린지 8일차  (0) 2022.01.31

라우터 ? 화면 처리기 만들기

 

기존의 웹이라면 현재 화면, 즉 현재 화면을 다른 화면으로 전환시 현재의 화면은 이전 화면이 되고 다른 화면이 현재의 화면이 된다. 하지만 지금 구현한 상태는 목록 화면과 내용 화면이 두개 다 보이는 형태이다.

 

라우터: 중계기, 상황에 따라 맞게 화면을 보여주는 역할을 한다.

 

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

function getData(url){
    
    ajax.open('GET', url, false); // method, Url, async
    ajax.send();

    return JSON.parse(ajax.response);
}

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

    newsList.push('<ul>');
    
    for(let i=0; i<newsFeed.length; i++){    
        newsList.push(`
            <li>
                <a href="#${newsFeed[i].id}">
                    ${newsFeed[i].title} (${newsFeed[i].comments_count})
                </a>
            </li>
        `);        
    }

    newsList.push('</ul>');

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

function newsDetail(){
    const id = location.hash.substring(1);

    const newsContent = getData(CONTENT_URL.replace('@id', id));
    const title = document.createElement('h1');        

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

function router(){
    const routePath = location.hash;

    if(routePath === ''){
        newsFeed();        
    }else{
        newsDetail();
    }
}

window.addEventListener('hashchange', router);

router();

기존의 코드에서 DOM API 방식을 전부 문자열 HTML 형식으로 수정했고 반복되고 재사용되는 코드들을 함수화했다. 기존에 목록 화면과 내용 화면이 공존하거나 내용 화면이 계속 추가되는 상태였는데, 함수화 작업을 통해 목록 화면 부분과 내용 화면 부분을 나눴고 router라는 함수를 통해 hashchange 이벤트 처리 시 목록 화면을 내보낼지 내용 화면을 내보낼지 중계 해주는 작업을 추가했다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 12일차  (0) 2022.02.04
패스트캠퍼스 챌린지 11일차  (0) 2022.02.03
패스트캠퍼스 챌린지 9일차  (0) 2022.02.01
패스트캠퍼스 챌린지 8일차  (0) 2022.01.31
패스트캠퍼스 챌린지 7일차  (0) 2022.01.30

추가 개선:

 

변수 = 데이터를 담는 그릇

객체 = 변수 여러개를 담을 수 있는 그릇

함수 = 코드를 담을 수 있는 그릇

 

: 리팩토링

const container = document.querySelector('#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';

function getData(url){
    
    ajax.open('GET', url, false); // method, Url, async
    ajax.send();

    return JSON.parse(ajax.response);
}

const newsFeed = getData(NEWS_URL)
const ul = document.createElement('ul');

window.addEventListener('hashchange', function(){
    const id = location.hash.substring(1);

    const newsContent = getData(CONTENT_URL.replace('@id', id));
    const title = document.createElement('h1');

    title.innerHTML = newsContent.title;

    content.appendChild(title);    
});

for(let i=0; i<newsFeed.length; i++){
    const div = document.createElement('div');    

    div.innerHTML = `
    <li>
        <a href="#${newsFeed[i].id}">
            ${newsFeed[i].title} (${newsFeed[i].comments_count})
        </a>
    </li>
    `;    
    
    ul.appendChild(div.firstElementChild);
}

container.appendChild(ul);
container.appendChild(content);

기존의 구조를 변경했다. ajax를 통해서 해커뉴스 서버의 데이터를 받아오는 방식을 특정한 곳에서나 여러번 사용 가능하도록 함수로 바꿨다. ajax나 fetch, axios 등의 서버에서 데이터를 가져오는 기능은 이벤트리스너 함수처럼 비동기로 처리해야 하지만 현재는 강의의 진행에따라 동기적인 방식으로 처리한다.

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 11일차  (0) 2022.02.03
패스트캠퍼스 챌린지 10일차  (0) 2022.02.02
패스트캠퍼스 챌린지 8일차  (0) 2022.01.31
패스트캠퍼스 챌린지 7일차  (0) 2022.01.30
패스트캠퍼스 챌린지 6일차  (0) 2022.01.29

문자열을 활용한 HTML 다루기

 

UI의 복잡해짐에 따라 (디자인, 기능 등 추가) 마크업 구조가 더 복잡해지는데 현재 코드의 문제점 등을 개선한다.

 

DOM API의 문제점: HTML의 구조와 코드를 보고 서로의 구조를 명확히 알기 힘들다.

 

DOM API를 최대한 사용하지 말자.

const container = document.querySelector('#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';

ajax.open('GET', NEWS_URL, false); // method, Url, async
ajax.send();

const newsFeed = JSON.parse(ajax.response);
const ul = document.createElement('ul');

window.addEventListener('hashchange', function(){
    const id = location.hash.substring(1);
    
    ajax.open('GET', CONTENT_URL.replace('@id', id), false);
    ajax.send();

    const newsContent = JSON.parse(ajax.response);
    const title = document.createElement('h1');

    title.innerHTML = newsContent.title;

    content.appendChild(title);    
});

for(let i=0; i<newsFeed.length; i++){
    const div = document.createElement('div');    

    div.innerHTML = `
    <li>
        <a href="#${newsFeed[i].id}">
            ${newsFeed[i].title} (${newsFeed[i].comments_count})
        </a>
    </li>
    `;    
    
    ul.appendChild(div.firstElementChild);
}

container.appendChild(ul);
container.appendChild(content);

기존의 DOM API 구조를 innerHTML을 통한 문자열 형태로 바꿨다. 이렇게 코드를 변경함으로 HTML구조와 코드의 구조를 알아보기 쉬워지고 기능이 추가되거나 코드의 양이 많아진다 하더라도 복잡도가 늘어난 것이 아니기 때문에 수월하게 내용을 파악할 수 있다.

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

'study' 카테고리의 다른 글

패스트캠퍼스 챌린지 10일차  (0) 2022.02.02
패스트캠퍼스 챌린지 9일차  (0) 2022.02.01
패스트캠퍼스 챌린지 7일차  (0) 2022.01.30
패스트캠퍼스 챌린지 6일차  (0) 2022.01.29
패스트캠퍼스 챌린지 5일차  (0) 2022.01.28

+ Recent posts