node -v : 노드 버전 확인
npm -v
: 외부에서 제공되는 여러 라이브러리들을 누릴 수 있다
파셀(Parcel) 번들러 설치 -> 설치방법 보기
https://ko.parceljs.org/getting_started.html
- 파셀: 주로 웹 개발에서 사용되는 도구 중 하나로, 여러 개의 리소스 파일(예: JavaScript, CSS, 이미지)을 하나의 번들(bundle)로 결합하는 도구
해커뉴스 api -> 포스트맨에서 사용
https://github.com/tastejs/hacker-news-pwas/blob/master/docs/api.md
- Postman은 API 개발 및 테스트를 위한 툴. API 요청을 생성하고 관리하며, API 응답을 테스트하고 문서화하는 데 사용
- ECMAScript 2015 (ES6): 읽어보기
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
- ECMAScript: JavaScript의 표준화된 버전을 정의하는 일련의 규격과 규칙을 나타내는 표준 스크립트 언어. JavaScript의 핵심 구문, 데이터 유형, 함수, 객체 및 다른 기능을 정의
js 셋팅방법(로컬 셋팅을 별도로 처리하는 방법)
: .vscode 폴더 생성 - settings.json 파일 생성 - 설정 코드 작성

{
"editor.fontsize": 20,
"[javascript]":{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.maxTokenizationLineLength": 2500
}
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<!-- 모바일 뷰포트 설정 지정 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>실습 - 뉴스API</title>
<!-- 외부 JavaScript 파일을 로드 -->
<script src="./index.js" defer></script>
</head>
<body>
<!-- id를 쓸 때는 #-->
<!-- innerHTML-->
<div id="root"></div>
</body>
</html>
<script src="./index.js" defer></script>
- defer: 페이지 파싱이 끝난 후 스크립트를 실행
- ./index.js: 상대경로.
(재사용성을 위해 절대경로보다 상대경로 쓴다)
console.log('hello parcel'); // 번들러(누가? 파셀이)
// XMLHttpRequest 객체를 생성하여 서버와 통신을 담당할 변수 'ajax'를 선언
const ajax = new XMLHttpRequest();
// API 엔드포인트(?) URL을 NEWS_URL 상수에 저장
const NEWS_URL = 'https://api.hnpwa.com/v0/news/1.json';
// HTTP GET 요청 설정 + 서버로 요청을 보냄
ajax.open('GET', NEWS_URL, true);
ajax.send();
// 서버로부터 받은 JSON 응답을 객체로 파싱하여 'newsList' 변수에 저장
const newsList = JSON.parse(ajax.response);
// 서버측에서 보낸 응답을 출력해 보기
// Array로 변환하여 출력해줌
console.log(newsList);
// ul: 순서나 계층을 나타내지 않는 목록
const ul = document.createElement('ul'); // DOM API를 가지고 태그를 만드니까 직관적이지 않다. DOM Tree 그려지지 않아서
// 'newsList' 배열의 각 요소에 대한 반복문 시작
for(let i=0;i<newsList.length;i++){
const li = document.createElement('li');
li.innerHTML = newsList[i].title;
ul.appendChild(li);
} // end of for
document.getElementById('root').appendChild(ul);
const ajax = new XMLHttpRequest();
const(constant): 상수. 한 번 값을 할당하면 이후 변경할 수 없으므로, 변수에 대한 불변성을 강제하는 역할
XMLHttpRequest: 비동기적으로 서버와 통신할 수 있는 기능을 제공하는 JavaScript 객체(브라우저가 비동기처리를 위해 제공하는 내장객체). 이 객체를 사용하면 웹 페이지에서 서버로 데이터를 보낼 수 있고, 서버로부터 데이터를 받아와 웹 페이지를 업데이트 할 수 있음
비동기 통신: XMLHttpRequest는 비동기적으로 데이터를 서버로 보내거나 서버로부터 데이터를 받아올 수 있음(웹 페이지가 브라우저를 차단하지 않고 계속 실행될 수 있게 함)
ajax.open('GET', NEWS_URL, true);
ajax.send();
const newsList = JSON.parse(ajax.response);
처리과정
1. ajax.response에 저장된 JSON 형식의 응답 데이터를 가져온다
JSON.parse() 함수를 사용하여 이 데이터를 해석하고, JavaScript 객체로 변환
이 객체를 newsList 변수에 할당. 이제 newsList에는 서버에서 가져온 데이터가 JavaScript 객체로 저장되어 있음. 이 객체를 이후에 사용하여 데이터를 화면에 표시하거나 다른 작업을 수행할 수 있음
for(let i=0;i<newsList.length;i++){
// 빈 목록 항목 생성
const li = document.createElement('li');
li.innerHTML = newsList[i].title;
// 생성한 li 요소를 <ul> 요소에 추가
ul.appendChild(li);
}
li.innerHTML = newsList[i].title;
ul.appendChild(li);
document.getElementById('root').appendChild(ul);
const ajax = new XMLHttpRequest();
const TITLE_URL = "https://api.hnpwa.com/v0/news/1.json";
const container = document.getElementById("root");
// 뉴스 comment를 담을 태그 생성
const content = document.createElement("div");
const CONTENT_URL = "https://api.hnpwa.com/v0/item/@id.json";
ajax.open("GET", TITLE_URL, true);
ajax.send();
// response 속성값도 XMLHttpRequest객체가 제공
const newsList = JSON.parse(ajax.response);
const ul = document.createElement("ul");
window.addEventListener("hashchange", () => {
console.log("해시변경되었나?");
const id = location.hash.substring(1);
console.log(id);
// 뒤에 아이디 자리에 #이 들어오면 안된다
ajax.open("GET", CONTENT_URL.replace("@id", id), false);
ajax.send();
const ncontent = JSON.parse(ajax.response);
const title = document.createElement("h1");
title.innerHTML = ncontent.title;
// 파라미터 자리에 변수가 왔다 - 싱글 쿼테이션은 없다
// 파라미터에 변수를 사용하면 대응하는 객체는 따로 존재함
// 기존에 태그 하위태그로 추가하는 함수이다
content.appendChild(title);
// 서버로부터 받은 데이터 객체를 로그에 출력
console.log(ncontent);
});
// 뉴스 목록에서 상위 5개 항목을 가져와 화면에 출력
for (let i = 0; i < 5; i++) {
const li = document.createElement("li");
const a = document.createElement("a");
a.href = `#${newsList[i].id}`;
// innerHTML을 통해서 a태그 내부에 텍스트노드를 결정
a.innerHTML = `${newsList[i].title}(🚨${newsList[i].comments_count})`;
li.appendChild(a); //<li><a>
ul.appendChild(li); // <ul><li>
} //end of for
// 두 개 화면으로 나눠보기
// <div id='root'>에 <ul>을 붙여달라는 것
container.appendChild(ul);
// appendChild는 기존에 있는 노드에 추가하기
container.appendChild(content);
// 객체를 생성했으니
const ajax = new XMLHttpRequest();
.
.
.
// 함수를 호출할 수 있다
ajax.open("GET", TITLE_URL, true);
// 뉴스 목록을 가져오는 것
const TITLE_URL = "https://api.hnpwa.com/v0/news/1.json";
// 뉴스에 대한 댓글 정보를 가져오는 것
const CONTENT_URL = "https://api.hnpwa.com/v0/item/@id.json";
const container = document.getElementById("root");
const content = document.createElement("div");
window.addEventListener("hashchange", () => {});
console.log(location.hash);
const id = location.hash.substring(1);
ajax.open("GET", CONTENT_URL.replace("@id", id), false);
title.innerHTML = ncontent.title;
content.appendChild(title);
//<h1>제목</h1> <div>내용</div>
// <div><h1> 제목{텍스트노드: 태그이름은 없고 값은 있다.}</h1> <div>내용</div>
-> 어떤 게 맞는지?
a.href = `#${newsList[i].id}`;
// <a href=' '> 이렇게 값을 지정해줄 수 있다
// 여기 들어갈 정보가 현재 없기 때문에</a>
a 링크의 href 속성을 설정하여 링크가 클릭될 때 브라우저의 해시(앵커)를 변경
newsList[i].id: 현재 반복 인덱스 i에 해당하는 뉴스 항목의 id 값을 가져와서 해당 id 값을 해시로 설정
a 링크의 href 속성: 해당 링크가 가리키는 URL 또는 웹 페이지의 위치를 정의
const ajax = new XMLHttpRequest();
const TITLE_URL = "https://api.hnpwa.com/v0/news/1.json";
const container = document.getElementById("root");
const content = document.createElement("div");
const CONTENT_URL = "https://api.hnpwa.com/v0/item/@id.json";
// @param: url - TITLE_URL or CONTENT_URL
// @return : Array(JSON->application/json - 파이썬으로 하든 c#을 하든)
getData = (url) => {
ajax.open("GET", url, true);
ajax.send();
return JSON.parse(ajax.response);
};
const newsList = getData(TITLE_URL);
console.log(newsList);
const ul = document.createElement("ul");
window.addEventListener("hashchange", () => {
console.log("해시변경되었나???");
const id = location.hash.substring(1);
console.log(id);
// url에 있으면 되니까 필요가 없음
// ajax.open("GET", CONTENT_URL.replace("@id", id), false); // 뒤에 아이디 자리에 #이 들어오면 안된다
// ajax.send();
const ncontent = getData(CONTENT_URL.replace("@id", id));
const title = document.createElement("h1");
title.innerHTML = ncontent.title;
content.appendChild(title);
console.log(ncontent);
});
for (let i = 0; i < 5; i++) {
const li = document.createElement("li");
const a = document.createElement("a");
a.href = `#${newsList[i].id}`;
//console.log(newsList[i].title);
a.innerHTML = `${newsList[i].title}(🚨${newsList[i].comments_count})`;
li.appendChild(a);
ul.appendChild(li);
}
container.appendChild(ul);
container.appendChild(content);
getData = (url) => {};
getData함수를 Arrow funcion으로 처리
- ES6(ECMAScript 2015)에서 도입된 JavaScript의 함수 선언 방식 중 하나
- 기존의 함수 선언 방식과 비교하면 간결하고 명확한 구문을 제공
ex) // 기존 함수 선언 function add(a, b) { return a + b; } // Arrow function const add = (a, b) => a + b;
const ajax = new XMLHttpRequest();
const TITLE_URL = "https://api.hnpwa.com/v0/news/1.json";
const container = document.getElementById("root");
const content = document.createElement("div");
const CONTENT_URL = "https://api.hnpwa.com/v0/item/@id.json";
getData = (url) => {
ajax.open("GET", url, true);
ajax.send();
return JSON.parse(ajax.response);
};
const newsList = getData(TITLE_URL);
console.log(newsList);
const ul = document.createElement("ul");
window.addEventListener("hashchange", () => {
const id = location.hash.substring(1);
const ncontent = getData(CONTENT_URL.replace("@id", id));
const title = document.createElement("h1");
title.innerHTML = ncontent.title;
content.appendChild(title);
});
for (let i = 0; i < 5; i++) {
const div = document.createElement("div");
div.innerHTML = `
<li>
<a href = "#${newsList[i].id}">
${newsList[i].title}(👌${newsList[i].comments_count})
</a>
</li>
`;
ul.appendChild(div.firstElementChild);
}
container.appendChild(ul);
container.appendChild(content);
ul.appendChild(div.firstElementChild);
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li><a href="http://www.naver.com">네이버</a></li>
<li><a href="http://www.google.com">구글</a></li>
</ul>
<script>
// 호출하지 않아도 자동실행됨. 왜냐하면 함수를 선언하지 않았잖아
location.href = "http://www.naver.com";
</script>
</body>
</html>
ajax.open("GET", TITLE_URL, true);
ajax.send();
// 함수의 이름을 정해줍시다
function getData(url){ // 왜 타입이 없을까? // js는, html은 컴파일(문법체크-타입체크)을 안하잖아
// 그럼 자바스크립트는 타입을 언제 결정하나요? -> 런타임시에 결정됨 - >true를 주면 boolean, 1을 주면 정수, 0.5를 주면 실수
// 실행은 누가 해준다? 브라우저
// 자바스트립트에서는 함수도 객체다 - 고차함수, 일급객체,
ajax.open("GET", CONTENT_URL.replace("@id", id), true);
ajax.send(); // 서버 측에 요청을 보내고 응답을 기다리는 중...
return JSON.parse 함수 이용해서 return JSON.parse(ajax.response);
}
-> 이걸 arrow function으로 바꾸자.
arrow function에서는 function 생략하자.
getData라는 함수명을 바로 쓰자. 파라미터 쓸 때 = () 붙이자.
함수명 = (파라미터 자리) => { // 파라미터는 생략 가능하다
실행문(변수선언, 재정의, 제어문)
}
함수 이름을 변수처럼 사용이 가능하다
getData = (url)
타입이 있지만 런타임시 결정. 또 컴파일이 없으니까(문법체크 안 하니까) 독이 될 수도 있다
// 데이터를 해커뉴스 서버에서 응답으로 받아와야 해
CONTENT_URL.replace("@id", id) 이게 중요하니 선언을 먼저
ajax.open("GET", CONTENT_URL.replace("@id", id), false);
ajax.send();
개선코드 1단계 - 반복되는 코드를 줄여봐요...
어떻게 줄일 수 있죠? - 함수를 선언하자
선언방법:
function 함수명(){}
이 함수를 서버에 요청을 할 때 쓰는 것
ex. 해커뉴스 서버에 뉴스정보를 요청할 때 사용함
요청을 한다는 건? 응답을 기다리는 것. 처리 결과를 받아와서 응답(Array (뉴스)30개)
리턴값을 받을 수 있는 코드가 추가되어야 한다.
function 함수명(){ return }
해커뉴스가 응답으로 JSON 포맷으로 데이터셋을 준다
const ajax = new XMLHttpRequest(); // ajax.open(), ajax.send()
자바에서 인스턴스변수 앞에서 적었던 것 처럼 ajax라는 변수 이름을 붙여준다
브라우저는 마임타입으로 알아본다
JSON(mime type: application/json, image/png, image/jpg, text/js, text/css...)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>실습 - 뉴스API</title>
<script src="./index.js" defer></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
const ajax = new XMLHttpRequest();
const TITLE_URL = "https://api.hnpwa.com/v0/news/1.json";
const container = document.getElementById("root");
const content = document.createElement("div");
const CONTENT_URL = "https://api.hnpwa.com/v0/item/@id.json";
// @param: url - TITLE_URL or CONTENT_URL
// @return : Array(JSON->application/json - 파이썬으로 하든 c#을 하든)
getData = (url) => {
ajax.open("GET", url, false);
ajax.send();
return JSON.parse(ajax.response); // JSON -> Array
};
const newsList = getData(TITLE_URL);
console.log(newsList);
const ul = document.createElement("ul");
window.addEventListener("hashchange", (event) => {
const id = location.hash.substring(1);
// 얘네 필요없다. url에 있으면 되니까
// ajax.open("GET", CONTENT_URL.replace("@id", id), false); // 뒤에 아이디 자리에 #이 들어오면 안된다
// ajax.send();
const ncontent = getData(CONTENT_URL.replace("@id", id));
const title = document.createElement("h1");
title.innerHTML = ncontent.title;
content.appendChild(title);
console.log(ncontent);
});
for (let i = 0; i < 5; i++) {
const li = document.createElement("li");
const a = document.createElement("a");
a.href = `#${newsList[i].id}`;
a.innerHTML = `${newsList[i].title}(🚨${newsList[i].comments_count})`;
li.appendChild(a);
ul.appendChild(li);
}
container.appendChild(ul);
container.appendChild(content);
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="s1.css">
</head>
<body>
<!-- .wrap > .box1 + .box2 -->
<!-- div 블록요소이다. 위 아래로 출력 -->
<div class="wrap">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
.wrap{
width: 300px;
height: 600px;
border: 10px solid black;
margin: 10px auto;
}
.wrap .box1 {
width: 300px;
height: 300px;
background-color: skyblue;
}
.box2 {
width: 300px;
height: 300px;
background-color: pink;
}
Q. 배치할 때 현재 레이아웃에 영향을 주지 않으면서 box1만 위로 50px 올라가기를 원한다면?
<정답>
.wrap .box1 {
width: 300px;
height: 300px;
background-color: skyblue;
position: relative; // 추가
top: -50px; // 추가
}
margin-top: -50px; // 추가
box1과 box2가 함께 이동한다
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Position- Relative</title>
<link rel="stylesheet" href="r1.css">
</head>
<body>
<article class="container">
<div></div>
<div class="box">Box</div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</article>
</body>
</html>
* {
border: 1px solid red;
}
.container {
background-color: black;
position: relative;
}
div {
width: 100px;
height: 100px;
background-color: skyblue;
margin-bottom: 10px;
}
.box {
background-color: orangered;
position: absolute;
left: 20px; /* x축으로 이동 */
top: 20px; /* y축으로 이동 */
}
position: relative;
.box {
background-color: orangered;
position: absolute;
left: 20px; /* x축으로 이동 */
top: 20px; /* y축으로 이동 */
}
position: absolute;
컨텐츠가 좌우로 배치되는 경우도 많다. div는 무조건 위아래로 배치가 되므로
강제로 float를 사용하여 좌우배치가 되도록 할 수 있다.
float설정시 부모요소가 자식 요소 높이값 인식시키는 방법
1. 부모요소에 강제 높이값 지정
:반응형으로 할때는 깨진다
2. 부모 요소에 overflow: auto;
:특정 브라우저에서 가로 세로 스크롤이 생길 수 있다
3. 부모 요소에 overflow: hidden
4. 부모 요소에 float설정
:left를 주면 왼쪽으로 붙고 right를 주면 오른쪽으로 붙음
5. float된 요소의 아래쪽에 배치되는 요소에 clear:both;적용
:bottom 요소가 필요없으면 의미 없다
6. 가상 선택자 ::after 를 이용해서 clear: both;
:이것이 권장 사항이다
clear: both는 취소하다 라는 개념으로 float: left/right와 짝꿍 개념이다
float 속성을 적용하면 그 이후에 오는 다른 요소들까지 똑같은 속성이 전달되어
둘러싼 형태가 되거나 부유된 영역 아래(under)로 들어가게 됨
float속성이 더 이상 사용하지 않고 그 전으로 되돌리고 싶다면 사용하는 것이
clear:both 임
clear: both; 오른쪽/왼쪽을 취소, 가장 많이 사용
clear: left; 왼쪽을 취소
clear: right; 오른쪽을 취소
clear: none; 기초값을 clear값을 설정하지 않은 것과 같다
float: left를 해제하기 위해서 clear:left 라고 지정하면 되지만
float속성값을 일일이 기억하기 번거롭기 때문에 보통 clear:both라고 지정함
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="a1.css">
</head>
<body>
<!--.wrap>.left+.right+.bottom-->
<div class="wrap">
<div class="left"></div>
<div class="right"></div>
<div class="bottom"></div>
</div>
</body>
</html>
.wrap {
width: 800px;
border: 10px solid black;
margin: 100px auto;
}
.left {
width: 400px;
height: 400px;
background-color: lightblue;
float: left;
}
.right {
width: 400px;
height: 400px;
background-color: lightpink;
float: left;
}
.wrap .bottom {
width: 800px;
height: 100px;
background-color: green;
clear: both;
}
.wrap::after {
content: "";
display: block;
clear: both;
}
float: left;
요소를 왼쪽으로 띄우는 속성
clear: both;
.wrap::after { }
.wrap 클래스의 가상 선택자: 특정 요소의 일부 또는 가상의 부분을 선택하는 데 사용
/* 가상선택자는 인라인요소이다
부모 요소에 무조건 가상선택자를 사용해서
부모요소가 자손요소를 감싸게 해줌
content: "";