시계 만들기
특정요소에서 찾기
document에서 어떤 요소를 찾을 때는 document.querySelector을 사용했지만, 어떤 요소에서 찾고 싶다면 해당 element에서 element.querlySelector을 하면 된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Carpediem</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="js-clock">
<h1 class="js-title">00:00</h1>
</div>
<script src="clock.js"></script>
</body>
</html>
const clockContainer = document.querySelector(".js-clock"),
clockTitle = clockContainer.querySelector("h1");
function getTime() {
const date = new Date();
const minutes = date.getMinutes();
const hours = date.getHours();
const seconds = date.getSeconds();
// 아래 코드 삼항연산자 포함
clockTitle.innerText = `${hours < 10 ? `0${hours}` : hours}:${
minutes < 10 ? `0${minutes}` : minutes
}:${seconds < 10 ? `0${seconds}` : seconds}`;
}
function init() {
getTime(); //초기화 과정에서 먼저 시간을 얻고,
setInterval(getTime, 1000); // 매 초마다 업데이트한다.
}
init();
위의 코드에서 주의할 점
- Date의 getMinutes와 getHours는 함수이다!!
- .innerText는 객체 안에 텍스트를 넣기 위해 사용한다.
setInterval
두 개의 argument 값을 받는 함수이다. 첫번째 인자로 실행할 함수를 받고 그리고 그 함수를 실행하고 싶은 시간 간격을 두번째 인자로 받는다. 따라서 형태는 아래와 같다. 단, 시간은 millisecond 단위이다. 따라서 1000 = 1초를 의미한다.
ternary operator (삼항연산자)
if의 역할을 수행해서 mini if라고도 볼 수 있다. 하나의 문자열로도 조건문을 쓸 수 있다는 것이 특징이다. 형식은 조건 ? true일 때 : false일 때 이다.
사용자의 컴퓨터에 정보 저장하기
Local Storage
작은 정보를 유저 컴퓨터에 저장하는 방법이다. Local Storage는 URLs를 기초로 동작한다.
null
true / false 의 종류와 비슷한 것으로 존재하지 않음을 의미한다. undefined, cannot find와 비슷하게 이해하면 된다.
예제) local storage에 정보가 있을 때 보이게 하기
<!--index.html-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width">
<title>Carpediem</title>
<link href="index.css" rel="stylesheet" />
</head>
<body>
<div class="js-clock">
<h1>00:00</h1>
</div>
<form class="js-form form">
<input type="text" placeholder="What is your name?"/>
</form>
<h4 class="js-greetings greetings"></h4>
<script src="clock.js"></script>
<script src="greeting.js"></script>
</body>
</html>
/*index.css*/
body{
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.form,
.greetings{
display: none;
/* display가 none 이면 보이지 않게 된다. */
}
.showing{
/*보이게 하기위해 display:block을 한다.*/
display: block;
}
//greeting.js
const form = document.querySelector(".js-form"), // (".js-form input") <-이런식으로도 사용할 수는 있다.
input = form.querySelector("input"),
greeting = document.querySelector(".js-greetings");
const USER_LS = "currentUser",
SHOWING_CN = "showing"; // .showing이 아니라는 사실을 주의하자
function paintGreeting(text) {
form.classList.remove(SHOWING_CN);
greeting.classList.add(SHOWING_CN);
greeting.innerText = `Hello ${text}`;
}
function loadName() {
// 이름이 없을 때만 입력 받으므로 localStorage에
// 이름의 존재여부를 먼저 체크해야한다.
const currentUser = localStorage.getItem(USER_LS);
if (currentUser === null) {
//이름이 있을 때 실행된다.
} else {
paintGreeting(currentUser);
}
}
function init() {
loadName();
}
init();
위의 코드 실행 결과
이름 입력받아 local Storage에 저장하기
무언가를 입력해서 enter을 눌러 정보를 넘긴다는 것은 form을 제출(submit)해야 한다는 것을 의미한다. input의 type이 text이여도 form으로 하면 user가 enter을 눌렀을 때 알아차리게 만들 수 있다. 다만 아무설정도 안했을 때 enter를 치면 웹사이트를 새로고침했을 때 같이 뜬다. 이것은 기본적으로 (by default) form을 제출하면 정보를 다른 곳으로 보내려고 하기 때문이다. 이러한 기본 설정을 지우려면 아래와 같이 하면 된다.
const form = document.querySelector(".js-form"),
input = form.querySelector("input"),
greeting = document.querySelector(".js-greetings");
const USER_LS = "currentUser",
SHOWING_CN = "showing";
function saveName(text){
localStorage.setItem(USER_LS, text);
}
function handleSubmit(event){
event.preventDefault();
const currentValue = input.value;
paintGreeting(currentValue); //여기까지 하면 local storage에 저장하지 않아 기억하지 못한다.
saveName(currentValue);
}
function askForName(){
form.classList.add(SHOWING_CN);
form.addEventListener("submit", handleSubmit);
}
function paintGreeting(text) {
form.classList.remove(SHOWING_CN);
greeting.classList.add(SHOWING_CN);
greeting.innerText = `Hello ${text}`;
}
function loadName() {
const currentUser = localStorage.getItem(USER_LS);
if (currentUser === null) {
askForName();
} else {
paintGreeting(currentUser);
}
}
function init() {
loadName();
}
init();
event.preventDefault()
👇🏻 [ 이벤트 전달 과정 자세히 보기 ]
보통 event가 발생하면 root에서 일어나고 form에서 일어난다. event는 마치 버블 같은 것이다. 이벤트가 올라가면서 다른 모든 것들이 event에 반응하게 되기때문이다. event가 계속 위로 올라가 document까지 가게 되고 그 document는 다른 곳으로 가게 될 것이다.
event.preventDefault() 는 어떤 요소의 기본 동작을 막기 위해 쓰이는 함수이다.
input.placeholder
input.placeholder을 통해 input의 placeholder 내용을 바꿀 수 있다.
input.value
input.value를 통해 input을 통해 입력된 현재 값을 얻을 수 있다.
👇🏻 [ .value vs .innerText vs .innerHTML ]
velog.io/@minjae-mj/Javascript-value-vs-textContent-innerHTML-innerText
button은 .value가 아닌 .innerText 이다.
To Do List 만들기
+) 이모지 입력방법
JS를 통한 html 요소 생성
document.createElement()
document에서 인자로 주는 html요소를 생성하는 함수이다.
element.appendChild()
어떤 요소에 자식 요소를 추가하고 싶을 때 사용하는 함수이다.
예시
const btn = document.createElement("button");
const span = document.createElement("span");
li.appendChild(btn);
li.appendChild(span);
위의 코드를 실행시키면 li의 자식으로 btn과 span이 추가된다.
+) 이모지가 잘못 출력 되었을 때
아래 코드를 작성했는지 확인해보자.
<meta charset="utf-8" />
예제 코드
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width">
<title>Carpediem</title>
<link href="index.css" rel="stylesheet" />
</head>
<body>
<div class="js-clock">
<h1>00:00</h1>
</div>
<form class="js-form form">
<input type="text" placeholder="What is your name?"/>
</form>
<h4 class="js-greetings greetings"></h4>
<form class="js-toDoForm">
<input type="text" placeholder="Write a to do" />
</form>
<ul class="js-toDoList">
</ul>
<script src="clock.js"></script>
<script src="greeting.js"></script>
<script src="todo.js"></script>
</body>
</html>
const toDoForm = document.querySelector(".js-toDoForm"),
toDoInput = toDoForm.querySelector("input"),
toDoList = document.querySelector(".js-toDoList");
const TODOS_LS = 'toDos'; // todo localstorage key name
function paintToDo(text){
const li = document.createElement("li");
const delBtn = document.createElement("button");
delBtn.innerText = "❌";
const span = document.createElement("span");
span.innerText = text;
li.appendChild(delBtn);
li.appendChild(span);
toDoList.appendChild(li);
}
function handleSubmit(event){
event.preventDefault();
const currentValue = toDoInput.value;
paintToDo(currentValue);
toDoInput.innerText = ""; // enter 쳤을 때 입력한 내용이 사라짐
}
function loadToDos(){
const toDos = localStorage.getItem(TODOS_LS);
if(toDos !== null){
}
}
function init(){
loadToDos();
toDoForm.addEventListener("submit", handleSubmit);
}
init();
To-do list 저장하기
array를 만들어 저장하는 방식을 사용한다. 유저가 todo를 입력하면 해당 내용을 배열에 추가하는 방식대로 하면 된다.
array.length
array의 길이를 array.length를 통해 알 수 있다. array 자리에 배열의 이름을 적어주면 된다. 그럼 그 이름을 가진 배열의 길이를 받을 수 있다. 여기서 배열의 길이란 배열 안에 든 요소의 개수를 의미한다. 인덱스와는 관련이 없다.
즉, 아래와 같다.
array.push
array.push를 통해서 배열에 내용을 넣을 수 있다.
Element.id
element의 id를 가져오거나 변경할 수 있다.
var idStr = elt.id; // 아이디를 가져옵니다.
elt.id = idStr; // 아이디를 부여합니다
Local storage의 Object 저장
위처럼 local storage에 object 정보를 저장할 때 [object Object]라고 저장되는 경우를 볼 수 있다. 이는 local storage에는 JS의 data를 저장할 수 없기 때문이다. 오직 string만 저장할 수 있다.
JSON
JavaScript Object Notation의 준말로, 데이터를 전달할 때 JS가 그걸 다룰 수 있도록 object로 바꿔주는 기능을 한다.
JSON.stringify()
JSON.stringify()는 JS object를 string으로 바꿔주는 함수이다.
JSON.parse()
JSON.parse()는 string을 object로 바꿔주는 함수이다.
array.forEach(함수이름)
array가 가진 함수 중 하나로, 배열에 담겨있는 것들 각각에 한번씩 인자의 함수를 실행시켜주는 함수이다.
인자 안에서 함수 생성하기
parsedToDos.forEach(function(toDo){
console.log(toDo.text);
}
);
위와 같이 함수의 이름을 생략하고 function(인자){ //실행내용 } <- 이렇게 사용할 수 있다.
local storage에 있는 To-Do를 html에 추가하여 새로고침해도 화면에 출력되도록 하기
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width">
<title>Carpediem</title>
<link href="index.css" rel="stylesheet" />
</head>
<body>
<div class="js-clock">
<h1>00:00</h1>
</div>
<form class="js-form form">
<input type="text" placeholder="What is your name?"/>
</form>
<h4 class="js-greetings greetings"></h4>
<form class="js-toDoForm">
<input type="text" placeholder="Write a to do" />
</form>
<ul class="js-toDoList">
</ul>
<script src="clock.js"></script>
<script src="greeting.js"></script>
<script src="todo.js"></script>
</body>
</html>
const toDoForm = document.querySelector(".js-toDoForm"),
toDoInput = toDoForm.querySelector("input"),
toDoList = document.querySelector(".js-toDoList");
const TODOS_LS = 'toDos'; // todo localstorage key name
const toDos = [];
function saveToDos(){
//배열 전체를 저장
localStorage.setItem(TODOS_LS, JSON.stringify(toDos));
}
function paintToDo(text){
const li = document.createElement("li");
const delBtn = document.createElement("button");
const span = document.createElement("span");
const newId = toDos.length + 1;
delBtn.innerText = "❌";
span.innerText = text;
li.appendChild(delBtn);
li.appendChild(span);
li.id = newId;
toDoList.appendChild(li);
// 여기까지가 할일에 대한 내용과 btn이 li에 추가 되고
// li가 ul에 추가되는 과정이다.
const toDoObj = {
text: text,
id: newId
}
toDos.push(toDoObj);
// todo list가 추가될 때 마다 배열의 전체를 다시 저장한다.
saveToDos();
}
function handleSubmit(event){
event.preventDefault();
const currentValue = toDoInput.value;
paintToDo(currentValue);
toDoInput.value = ""; // enter 쳤을 때 입력한 내용이 사라짐
}
function loadToDos(){
const loadedToDos = localStorage.getItem(TODOS_LS);
if(loadedToDos !== null){
const parsedToDos = JSON.parse(loadedToDos);
parsedToDos.forEach(function(toDo){
paintToDo(toDo.text);
});
}
}
function init(){
loadToDos();
toDoForm.addEventListener("submit", handleSubmit);
}
init();
To-Do 지우기
To-Do를 지우기 위해서는 먼저 local storage에 저장되어 있는 내용을 지워야 하고 HTML에서도 지워야 한다.
event.target
해당 event의 target이 된 html 요소를 알 수 있다.
event.target.parentNode
target을 포함하여 target의 부모까지 얻을 수 있다.
Node.removeChild()
👇🏻 [ 관련 MDN ]
함수의 이름처럼 자식을 지울 때 사용한다.
array.filter()
filter()는 배열에 사용하는 함수로 forEach() 함수처럼 각각의 item에 인자로 준 함수를 실행한다. filter()은 인자로 준 함수에서의 결과가 true인 item을 모아 배열을 만들어 return 한다.
function filterFn(){
return toDo.id === 1
}
function deleteToDo(event){
const btn = event.target;
const li = btn.parentNode;
toDoList.removeChild(li);
const cleanToDos = toDos.filter(filterFn);
}
위의 코드를 실행하면 toDos 배열의 item에 각각 filterFn 함수를 실행시켜 toDo.id가 1인 경우만 true를 반환하게 되는데 그것을 배열의 형식으로 저장시켜 return 한다.
parseInt()
string인 것을 int 형으로 바꿔주는 함수이다.
사진 배경 넣기
사진을 먼저 다운 받아 소스코드 파일이 든 폴더에 img 폴더를 만들고 그 안에 넣는다. 이미지가 로딩되면서 화면에 출력 될 때 툭툭 끊기면서 로딩된다면 좋지 않을 것이다. 이미지의 로딩이 완료된 후 유저에게 보여주는 방식으로 한다면 이러한 문제를 해결 할 수있다.
난수 얻기
Math
JS의 모듈 중 하나로 수학과 관련된 연산을 하는 함수가 있다.
- Math.random() : 임의적으로 숫자가 생성된다. ( 0이상 1미만의 수 )
- Math.floor() : 인자로 받은 수를 버림하여 return 한다.
- Math.ceil() : 인자로 받은 수를 올림하여 return 한다.
Math.random()
원하는 범위의 수를 나오게 하고 싶다면 *(곱하기) 연산을 활용하면 된다. Math.random() 은원하는 범위의 수를 나오게 하고 싶다면 *(곱하기) 연산을 활용하면 된다. Math.random() *5를 하면 0.00..~4.999..까지의 수가 나오게 된다. 따라서 버림을 이용할 경우 0~4까지의 수를 얻을 수 있다. 총 숫자의 개수는 5개가 된다. 따라서 얻고 싶은 숫자의 개수만큼 Math.random() 에 곱해주면 된다.
Math.floor()
Math.floor(3.9)는 3을 return 한다. 즉, 버림을 수행한다.
Math.ceil()
Math.ceil(3.1)은 4를 return 한다. 즉, 올림을 수행한다.
loadend
api에서 다운로드 받는 경우만 loadend event를 들을 수 있다. 따라서 아래 코드에서 표시한 부분은 의도한 대로 실행되지 않는다.
const body = document.querySelector("body");
const IMG_NUMBER = 5;
function handleImageLoad(){
console.log("finsihed loading");
}
function paintImage(imgNumber){
const image = new Image(); // functionally same as document.createElement("img")
// 여기서 random으로 생성한 number은 0부터 4까지이기 때문이다.
image.src = `img/${imgNumber+1}.jpg`;
image.addEventListener("loadend", handleImageLoad);
body.appendChild(image);
}
function genRandom(){
const number = Math.floor(Math.random()*IMG_NUMBER);
return number;
}
function init(){
const randomNumber = genRandom();
paintImage(randomNumber);
}
init();
Element.prepend()
element를 부모로 하여 첫번째 자식으로 인자 안의 요소를 넣는 함수이다.
z-index
요소들이 쌓이는 순서들을 나타내는 값으로 auto로 하면 박스가 새로운 쌓임 맥락을 생성하지 않는다. 현재 쌓임 맥락에서의 위치는 부모 요소와 동일합니다. 즉, 부모를 기준으로 자식의 순서와 동일하다. 첫번째 자식이 가장 아래로 간다. 또한 음수 값으로 우선순위를 낮출 수 있다.
예제 코드
body{
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
background-color: #2c3e50;
}
h4{
color: whitesmoke;
}
.js-clock{
color: whitesmoke;
}
.form,
.greetings{
display: none;
/* display가 none 이면 보이지 않게 된다. */
}
.showing{
/*보이게 하기위해 display:block을 한다.*/
display: block;
}
@keyframes fadeIn{
from{
opacity: 0;
}
to{
opacity: 1;
}
}
.bgImage{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
animation: fadeIn 2s linear;
}
const body = document.querySelector("body");
const IMG_NUMBER = 5;
function paintImage(imgNumber){
const image = new Image(); // functionally same as document.createElement("img")
// 여기서 random으로 생성한 number은 0부터 4까지이기 때문이다.
image.src = `img/${imgNumber+1}.jpg`;
image.classList.add("bgImage");
body.prepend(image);
}
function genRandom(){
const number = Math.floor(Math.random()*IMG_NUMBER);
return number;
}
function init(){
const randomNumber = genRandom();
paintImage(randomNumber);
}
init();
API를 통한 날씨정보 받아오기
위치(Geolocation) 얻어오기
navigator 의 api를 이용하여 얻을 수 있다. (+) navigator와 비슷한 것으로는 window, document가 있다.
navigator.geolocation
geolocation은 객체(object)로 getCurrentPosition, watchPostion 등의 함수를 가지고 있다.
navigator.geolocation.getCurrentPosition()
getCurrentPosition()은 함수로 2개의 requirements가 있다. ( 즉, 2개의 인자를 필수로 필요로 한다. ) 첫 번째는 좌표를 가져오는데 성공했을 때를 처리하는 함수이다. 두 번째는 좌표를 가져오는데 실패했을 때를 처리하는 함수이다.
function handleGeoSucces(position){
console.log(position);
}
function handleGeoError(){
console.log("Can't access geo location");
}
function askForCoords(){
navigator.geolocation.getCurrentPosition(handleGeoSucces, handleGeoError);
}
위와 같이 handleGeoSucces (handleGeoError도 원한다면 가능)의 인자를 주면 getCurrentPosition에서 얻은 position에 대한 정보를 넘겨 받아 함수 안에서 활용할 수 있다.
object에 정보 저장시 변수이름과 객체 key 이름이 같을 때
function handleGeoSucces(position){
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
const coordsObj = {
latitude: latitude,
longitude : longitude
};
}
function handleGeoSucces(position){
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
const coordsObj = {
latitude,
longitude
};
}
위와 같이 줄여 적을 수 있다. 위와 아래의 코드는 모두 동일한 것을 나타낸다.
API 사용하기
API(Application Programming Interface)는 다른 서버로부터 손쉽게 데이터를 가져올 수 있는 수단이다. API는 특정 웹사이트로부터 데이터를 얻거나 컴퓨터끼리 소통하기 위해 고안된 것이다. JS는 웹사이트로 request를 보내고 응답을 통해서 데이터를 얻을 수 있다. 이렇게 가져온 데이터를 refresh 없이도 웹사이트에 적용시킬 수 있다. 예를 들어 웹사이트를 새로고침하지 않아도 실시간으로 메일이 오는 것을 확인 할 수 있는 것이 있다.
날씨 API key 받아오기
https://openweathermap.org/ 에 들어가 가입을 하고 자신의 key 값을 복사한다. 그리고 이를 상수로 weather.js 파일 가장 상단에 입력한다.
fetch()
데이터를 얻기 위해서 fetch()라는 함수를 사용하면 된다. 인자로는 가져올 데이터가 들어가면 된다. 앞에는 https:// 를 넣어줘야 한다.
섭씨온도로의 단위 변경
api 사이트에 가면 단위 변경에 대한 설명이 나와있다. 이 예제에서는 api key 다음에 &units=metric을 추가하면 된다.
then()
데이터가 우리에게 넘어 왔을 때 실행되는 함수이다. then()은 기본적으로 함수를 호출하는 역할만 하지만 데이터가 완전히 들어온 다음 호출한다는 특징이 있다. 인자로는 호출하고 싶은 함수를 적어주면 된다. 형태의 예시는 아래와 같다.
fetch(
`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric`
).then(function(json){
console.log(json);
});
만약 fetch를 기다리지 않고 다음 작업을 지시하면, 다음 작업은 fetch가 완료될 때까지 기다리지 않고 바로 실행한다. 데이터가 다 로딩되고 작업을 수행하고 싶다면 then을 사용해주면 된다.
위 포스팅은 노마드 코더 "바닐라 JS로 크롬 앱 만들기" 강의를 토대로 만들어진,
[바닐라 JS 기초 개념 요약 정리] 입니다.
직접 강의를 보고 싶거나 자세한 사항을 알고 싶다면 아래 링크를 참고해주세요 😊
nomadcoders.co/javascript-for-beginners
'프로그래밍 > JS' 카테고리의 다른 글
[바닐라 JS 기초] 조건문 ( + ClassList, Toggle ) (0) | 2021.03.30 |
---|---|
[바닐라 JS 기초] DOM, Event (0) | 2021.03.30 |
[바닐라 JS 기초] 함수 (0) | 2021.03.30 |
[바닐라 JS 기초] JS와 바닐라JS, 출력, 변수, 데이터타입 (11) | 2021.03.30 |