변하지 않는 기술
네트워크, 운영체제, 컴퓨터시스템, 논리학, 대수학
느리게 변하는 기술
프로그래밍 언어, 프로그래밍 패러다임, 자료구조, 보안, 알고리즘
빠르게 변하는 기술
프레임워크, 라이브러리, UI, UX, 디자인패턴
4가지 프로그래밍 역량
일관성, 유연성, 확장성, 독립성
서버 없음 -> 해커뉴스 API
https://hnpwa.com/
https://github.com/tastejs/hacker-news-pwas
디자인 -> tailwindcss
비동기 메커니즘 -> 필수적 매커니즘이지만, hacker 프로젝트에서만 제외!
const ajax = new XMLHttpRequest();
ajax.open("GET","https://api.hnpwa.com/v0/news/1.json", false);
ajax.send();
console.log(ajax.response);
🚨 parcel이 바로 안되어 그냥 Liveserver로 하였더니... CORS문제....
일단, parcel 을 설치해보자!
💚 해결!
Network탭 에서 -> news?page=2 -> Response 콘솔에 찍혔던 받아온 그대로의 데이터
Network탭 에서 -> news?page=2 -> Preveiw 자바스크립트로 다루기 쉬운 방식으로 바뀌어진 형식으로 미리보여주는 탭
이와같이 코드로 짠다면 ?
const newsFeed = JSON.parse(ajax.response);
console.log(newsFeed);
const newsFeed = JSON.parse(ajax.response);
const ul = document.createElement("ul");
for (let i = 0; i < 11; i++) {
const li = document.createElement("li");
li.innerHTML = newsFeed[i].title;
ul.appendChild(li);
}
document.getElementById("root").appendChild(ul);
현재까지의 화면
window.addEventListener("hashchange", function () {
console.log("해시가 변경됨");
});
window.addEventListener("hashchange", function () {
const id = this.location.hash.substr(1);
ajax.open("GET", CONTENT_URL.replace("@id", id), false);
ajax.send();
const newsContent = JSON.parse(ajax.response);
console.log(newsContent);
});
이제, 콘텐츠를 불러왔으니까 화면에 어떻게 표현할 것인가를 결정해야지!
1. 콘텐츠를 표현할 영역을 만들고 + 2. 그 영역에 타이틀만 얹히는 형태
const content = document.createElement("div");
window.addEventListener("hashchange", function () {
const id = this.location.hash.substr(1);
ajax.open("GET", CONTENT_URL.replace("@id", id), false);
ajax.send();
const newsContent = JSON.parse(ajax.response);
const title = this.document.createElement("h1");
title.innerHTML = newsContent.title;
content.appendChild(title);
});
document.getElementById("root").appendChild(ul);
for (let i = 0; i < 11; i++) {
const div = document.createElement("div");
const li = document.createElement("li");
const a = document.createElement("a");
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);
함수를 만들고 그 함수가 할 일의 코드를 묶어 주고 그 코드가 동작되기 위한 입력 값을 정의해서 사용해 주고 그리고 함수의 처리 결과를 return으로 반환해 주고!
ajax.open("GET", NEWS_URL, false);
ajax.send();
const newsFeed = JSON.parse(ajax.response);
//리팩토링
function getData(url) {
ajax.open("GET", url, false);
ajax.send();
return JSON.parse(ajax.response);
}
const newsFeed = getData(NEWS_URL);
const newsContent = getData(CONTENT_URL.replace("@id", id));
//글 목록화면
const newsList = [];
newsList.push("<ul>");
for (let i = 0; i < 10; 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 newsFeed() {
//글 목록화면
const newsFeed = getData(NEWS_URL);
const newsList = [];
newsList.push("<ul>");
for (let i = 0; i < 10; 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 router() {
const routePath = location.hash;
if (routePath === '') {
newsFeed();
} else {
newsDetail();
}
}
window.addEventListener('hashchange', router);
router();
const store = {
currentPage: 1,
};
//글 목록화면
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 > store.currentPage - 1
? store.currentPage + 1
: store.currentPage
}'>다음 페이지</a>
</div>
`);
container.innerHTML = newsList.join("");
}
//글 내용화면
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 routePath = location.hash;
if (routePath === "") {
newsFeed();
} else if (routePath.indexOf("#/page/") >= 0) {
store.currentPage = Number(routePath.substr(7));
newsFeed();
} else {
newsDetail();
}
}
window.addEventListener("hashchange", router);
router();
//글 목록화면
function newsFeed() {
const newsFeed = getData(NEWS_URL);
const newsList = [];
let template = `
<div class="container mx-auto p-4">
<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);
template = template.replace('{{__next_page__}}', store.currentPage + 1);
container.innerHTML = template;
}