- Published on
Vanilla JS로 크롬앱 만들기 정리
- 글쓴이
📌 목차
- Why JS?
- Welcome to Js : Variable, Array, Object
- Js on the browser
- Login
- Clock
- Quotes and Background
- TODO list
- WEATHER
Why JS?
자바스크립트는 강력하다.
- 모든 브라우저에 자바스크립트가 내장되어 있기 때문이다. 웹개발을 하고 싶다면 자바스크립트를 공부해야 한다.
- 자바스크립트로 아주 멋있는 프로젝트( ex) 3d.js 사용)를 할 수 있고, 프론트엔드 뿐 아니라 앱개발, 백엔드 개발에도 쓰인다.
Welcome to Js
Variable
- 변수는 값을 담거나 유지하는 역할을 한다.
- 변수의 네이밍은 camel case가 일반적이다.
let
과const
를 사용해 변수를 선언하지만,var
는 사용하지 않아야 한다. 언어가 값의 변화를 체크해주지 않아 위험하다.
Array
- 하나의 그룹으로 관리하고자하는 데이터를 묶을 수 있는 그릇이다.
- 타입에 상관 없이 Array를 구성할 수 있다.
- 0 부터 시작하는 index를 통해 값에 접근하고, 없는 인덱스에 접근하면
undefined
가 출력된다.
const arr = [1,"a",null,undefined,1.0];
Object
때로는 단순히 순서가 정해진 하나의 그룹으로 관리하는 것이 적절하지 않을 수도 있다. Coder가 있고, Coder는 name과 쓸 수 있는 programming language, age가 있다고 가정한다.
const coder = ['Tina','java','kotlin',26]
위 정보는 coder와 어떤 연관성이 있는지 명확하지 않다. 그래서 의미와 값을 함께 가진 Object가 해당 데이터를 나타내기 적당하다.
coder.name = 'Tina'
coder.lang = ['java','kotlin','python']
coder.age = 26
위 내용을 자바스크립트로 표현하면 다음과 같다.
const coder = {
name : "Tina",
age : 26,
lang : ['java','kotlin','python']
}
console.log(coder.name); // Tina
console.log(coder["name"]); // Tina
coder.lang.push('js'); // ['java','kotlin','python','js']
Js on the browser
document
html 을 js의 관점에서 볼 수 있는 object이다. 자바스크립트가 기본으로 제공하는 document
를 통해 dom요소에 접근할 수 있다.
document.body
document.location
document.title
...
document를 기반으로, 웹페이지의 요소를 읽어오거나, 수정하거나, 추가할 수 있게된다. console창에 위와 같이 입력하면 현재 페이지의 타이틀이 바뀌는 것을 볼 수 있다.
document.title = "내맘대로 타이틀"
요소를 가져오는 방법
getElementById
등의 함수도 있지만 querySelector
와 querySelectorAll
을 더 많이 사용한다.
요소를 구체적으로 명시하기 편하기 때문이다.
const h1 = document.querySelector('.hello:first-child h1');
이벤트 추가하기
function handleH1Click() {
h1.innerHTML = "Mouse is clicked!";
const currentColor = h1.style.color;
let newColor;
if(currentColor === 'violet'){
newColor = 'tomato';
}
else {
newColor = 'violet';
}
h1.style.color = newColor;
}
function handleH1Enter() {
h1.innerHTML = "Mouse is here!";
h1.style.color = 'blue';
}
function handleH1Leave() {
h1.innerHTML = "Mouse is out!";
h1.style.color = 'skyblue'
}
h1.addEventListener("click",handleH1Click);
h1.addEventListener("mouseenter",handleH1Enter);
h1.addEventListener("mouseleave",handleH1Leave);
console.dir(h1);
console.dir
을 통해 on으로 시작하는 함수를 찾으면 해당 요소에서 사용할 수 있는 다양한 이벤트를 찾을 수 있다.
window
window
도 document
와 같이 javascript에서 기본으로 제공하는 객체이다. window
는 현재 자바스크립트가 돌아가고 있는 웹 페이지의 창
을 의미한다.
function handleWindowResize() {
document.body.style.backgroundColor = "#ccc";
}
function handleWindowCopy() {
alert("copied!");
}
function handleOffline() {
alert("SOS no wifi");
}
function handleOnline() {
alert("connected wifi");
}
window.addEventListener("resize",handleWindowResize);
window.addEventListener("copy",handleWindowCopy);
window.addEventListener("offline",handleOffline);
window.addEventListener("online",handleOnline);
css
위 예시에서는 js에서 직접적으로 스타일을 바꿔줬지만, 스타일은 css에서 전담하는 것이 권장된다고 한다.
body {
color: cornflowerblue;
}
.active {
color : tomato;
}
스타일을 javascript에서 html요소를 접근하는 방식으로 풀어나가는 것이 보다 적절하다. 아래는 contains, remove, add를 이용하는 방법을 toggle을 통해 한 줄로 줄인 모습이다.
function handleH1Click() {
// const activeClass = "active";
// if(h1.classList.contains(activeClass)===activeClass) {
// h1.classList.remove(activeClass);
// }
// else {
// h1.classList.add(activeClass);
// }
h1.classList.toggle("active")
}
Login
사용자에게 이름을 입력 받는 코드를 작성하였다. 사용자의 입력값은 언제든 믿으면 안되기 때문에 언제든지 유효성
검사를 하는 것은 좋은 습관이다.
const loginInput = document.querySelector("#login-form input");
const loginButton = document.querySelector("#login-form button");
function onLoginBtnClick() {
const value = loginInput.value;
if (value === "") {
alert("please write your name");
} else if (value.length > 15) {
alert("Your name is too long");
}
}
loginButton.addEventListener("click", onLoginBtnClick);
다만, 이번 케이스에서는 html에서 기본으로 지원하는 required
와 maxlength
옵션을 사용할 수도 있다. 값을 입력하지 않으면 입력하라는 자체 메세지가 뜨고, 최대길이를 넘어가면 더이상 입력되지 않는다.
<form id="login-form">
<input required maxlength="15" type="text" placeholder="What is your name?"/>
<button>Log In</button>
</form>
아래는 유저의 input을 받아 해당 input을 이용하는 코드이다.
...
.active {
color : tomato;
}
.hidden {
display: none;
}
...
<body>
<form id="login-form">
<input required maxlength="15" type="text" placeholder="What is your name?"/>
<button>Log In</button>
</form>
<h1 class="hidden" id="greeting"></h1>
</body>
const greeting = document.querySelector("#greeting");
const HIDDEN_CLASS = "hidden"
function onLoginsubmit(event) {
event.preventDefault();
console.log(event);
const userName = loginInput.value;
loginForm.classList.add(HIDDEN_CLASS);
greeting.classList.remove(HIDDEN_CLASS);
greeting.innerHTML = `Hello ${userName}!`;
}
event.preventDefault()
는 기본적으로 브라우저에 내장된 작업을 실행하지 않겠다는 뜻이다.
submit되면 창을 새로고침하고, html checkbox를 체크되는 등의 default
액션을 방지하고 프로그래머의 논리에 따라 작업을 수행하겠다는 뜻이다.
localStorage
setItem
, getItem
, removeItem
을 이용해 key-value의 형태로 값을 저장할 수 있다. 저장된 데이터는 개발자도구의 Application > Local Storage메뉴를 참조하면 된다.
아래 코드는 username이 localStorage 저장여부에 따라 보이는 요소가 달라지도록 한 것이다.
const greeting = document.querySelector("#greeting");
const HIDDEN_CLASS = "hidden";
const USERNAME_KEY = "username";
const savedUsername = localStorage.getItem(USERNAME_KEY);
if (savedUsername === null) {
loginForm.classList.remove(HIDDEN_CLASS);
loginForm.addEventListener("submit", onLoginsubmit);
} else {
paintGreetings();
}
function paintGreetings() {
loginForm.classList.add(HIDDEN_CLASS);
greeting.classList.remove(HIDDEN_CLASS);
greeting.innerText = `Hello ${savedUsername}!`;
}
function onLoginsubmit(event) {
event.preventDefault();
const userName = loginInput.value;
localStorage.setItem(USERNAME_KEY, userName);
paintGreetings(userName);
}
Clock
interval vs timeout
interval은 액션의 일정한 주기를 의미한다. 아래 코드는 1초마다 console에 hello는 메세지가 띄워진다.
function sayHello() {
console.log("hello");
}
setInterval(sayHello,1000);
timeout은 액션이 일정한 시간 뒤에 이루어지는 것을 의미한다. 사용방식은 interval과 비슷하지만 한번만 실행된다.
function sayHello() {
console.log("hello");
}
setTimeout(sayHello,1000);
Date
js에서는 기본적인 시간 관련 객체를 제공한다.
new Date();
const clock = document.getElementById("clock");
function getClock() {
const date = new Date();
const hours =date.getHours();
const mins = date.getMinutes();
const secs = date.getSeconds();
const time = `${hours}:${mins}:${secs}`;
console.log(time);
clock.innerText =time;
}
getClock();
setInterval(getClock,1000);
padStart() , padEnd()
const clock = document.getElementById("clock");
function getClock() {
const date = new Date();
const hours =date.getHours().toString().padStart(2,"0");
const mins = date.getMinutes().toString().padStart(2,"0");
const secs = date.getSeconds().toString().padStart(2,"0");
const time = `${hours}:${mins}:${secs}`;
clock.innerText =time;
}
getClock();
setInterval(getClock,1000);
Quotes and Background
Math
js에서 제공하는 수학관련 함수들이 있다.
- Math.floor() : 내림
- Math.round() : 반올림
- Math.ceil() : 올림
- Math.random() : 0~1 사이의 랜덤한 실수
- Math.abs(a) : a의 절댓값
- Math.pow(x,y) : x^y
Math.random() 사용하기
<div id="quotes">
<span></span>
<span></span>
</div>
const quote = document.querySelector("#quotes span:first-child");
const author = document.querySelector("#quotes span:last-child");
const randomNum = Math.floor(Math.random() * quotes.length);
const todaysQuote = quotes[randomNum].quote;
const todaysAuthor = quotes[randomNum].author;
quote.innerText = todaysQuote;
author.innerText = todaysAuthor;
createElement, appendChild 사용하기
const images = ["0","1","2","3","4","5"];
const randomImg = Math.floor(Math.random() * (images.length-1));
const todaysImg = `${images[randomNum]}.jpeg`;
const bgImage = document.createElement("img");
bgImage.src = `img/${todaysImg}`;
document.body.appendChild(bgImage);
TODO list
JSON.stringify, JSON.parse
stringify는 자바스크립트의 객체, 배열을 JSON string으로 변환시켜주는 함수이다. localStorage에는 배열이나 객체가 저장될 수 없기에 해당 함수를 사용한다. parse는 string을 자바스크립트 데이터로 바꿔주는 함수이다.
const TODOS_KEY = "todos";
let todos = [];
const saveTodosStr = localStorage.getItem(TODOS_KEY);
function saveTodos() {
localStorage.setItem(TODOS_KEY,JSON.stringify(todos));
}
function deleteTodo(event) {
const li = event.target.parentElement;
todos = todos.filter((todo)=> todo.id !== parseInt(li.id)) ;
li.remove();
saveTodos();
}
function paintTodo(newTodo) {
console.log(newTodo);
const li = document.createElement("li");
const span = document.createElement("span");
const button = document.createElement("button");
span.innerText = newTodo.text;
button.innerText = "x";
li.id = newTodo.id;
li.appendChild(span);
li.appendChild(button);
button.addEventListener("click",deleteTodo);
toDoList.appendChild(li);
}
function handleTodoSubmit(e) {
e.preventDefault();
const newTodo = toDoInput.value;
toDoInput.value = "";
const idStr = Date.now().toString();
console.log(newTodo,idStr);
const newTodoObj = {
id : idStr,
text : newTodo,
};
if(todos===null) todos =[];
todos.push(newTodoObj);
paintTodo(newTodoObj);
saveTodos();
}
WEATHER
navigator는 브라우저에 대한 다양한 정보를 제공하는 객체이다.
const weather = document.querySelector("#weather span:first-child");
const city = document.querySelector("#weather span:last-child");
const API_KEY = "blahblah";
function onGeoOk(position) {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
const lon = position.coords.longitude;
const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric`;
fetch(url)
.then((response) => response.json())
.then((data) => {
city.innerText = data.name;
weather.innerText = `${data.weather[0].main} / ${data.main.temp}`;
});
}
function onGeoError() {
alert("Can't find you. No weather for you.");
}
navigator.geolocation.getCurrentPosition(onGeoOk, onGeoError);
궁금증
todo array is null ? (파일 상단에서 초기화를 해줬음에도:
let todos =[];
)
defer 옵션으로 js를 로딩한 상태에서 파일 상위에 초기화한 todo array가 null 로 떠서 해당 에러가 나는 줄에 초기화 코드(if(todos===null) todos =[];
)를 넣어주니 해결되었다.
todo null과 관련된 부분은 let todos = []
와 filter뿐이다. 이전에 동일한 로직으로, 한 js파일에서 개발한 코드에서는 잘 돌아갔는데, 로딩시점의 문제인지 추측만 하는 중이다.
발전을 위한 링크