#Javascript #바닐라JS
안녕하세요. Gi_1입니다.
노마드코더의 무료 자바스크립트 강의, 바닐라 JS로 크롬 앱 만들기 코드 정리 입니다.
무료강의를 신청하면 메일로 퀴즈가 날라온다는데.. 저는 몰랐어서 안하는 바람에 재신청해서 하고 있습니다 ㅎ;;
몇번 안하면 실패!!하면서 기회가 없고 다시 신청해야하니 강의를 들으실 분들은 참고 해주세요.
미리보기
오른쪽 위에는 사용자의 위치 / 날씨 / 기온이 나타납니다.
이름을 입력하여 로그인 할 수 있으며 일정을 기록 할 수 있습니다.
새로고침을 할 때 마다, 배경사진과 제일 하단의 명언이 교체됩니다.
이는 백앤드를 필요로 하지 않고, 새로고침을 해도 유지가 됩니다. ( 쿠키 삭제 등을 하면 사라집니다. )
#어떻게 입력된 정보가 자바스크립트만으로 저장 되는가??
-> localStorage 사용
HTML
< div class = "main_wrap" >
< div class = "main_inner" >
< h1 id = "greeting" class = "hidden" >
</ h1 >
< form id = "login-form" class = "hidden" >
< input type = "text" placeholder = "성함을 입력하세요." required maxlength = "15" >
< input type = "submit" value = "Log In" >
</ form >
< h2 id = "clock" >
00:00:00
</ h2 >
< form id = "todo-form" >
< input type = "text" placeholder = "일정을 입력하세요." required >
</ form >
< ul id = "todo-list" >
</ ul >
</ div >
</ div >
< div id = "quoteBox" class = "quoteBox" >
< span class = "quote_en" ></ span >< br >
< span class = "quote_ko" ></ span >
</ div >
< div id = "weather" >
< span class = "weather_weather" ></ span >
< span class = "weather_place" ></ span >
</ div >
< script src = "js/greetings.js" ></ script >
< script src = "js/clock.js" ></ script >
< script src = "js/quotes.js" ></ script >
< script src = "js/background.js" ></ script >
< script src = "js/todo.js" ></ script >
< script src = "js/weather.js" ></ script >
greetings.js (로그인 부분)
const loginForm = document . querySelector ( "#login-form" );
const loginInput = document . querySelector ( "#login-form input" );
const loginButton = document . querySelector ( "#login-form button" );
const greeting = document . querySelector ( "#greeting" );
// document.getElementById 등은 css처럼 선택할 수 없으니 querySelector를 자주 이용한다고 함.
const HIDDEN_CLASSNAME = "hidden" ;
const USERNAME_KEY = "username" ;
// 2번이상 사용될 텍스트의 경우 변수로 지정해서 사용, 변수에 오타가 있을 경우에는 개발자 도구에서 오류가 발생 하지만, 변수로 사용하지 않고 그냥 오타가 날 경우 오류가 개발자 도구에서 나타나지 않음.
function paintGreetings ( username ){
greeting . innerText = `안녕하세요, ${ username } 님.` ;
greeting . classList . remove ( HIDDEN_CLASSNAME );
}
// onLoginSubmit에서 username을 받거나, 저장되어 있는 값(SavedUsername)이 있을 경우 사용
function onLoginSubmit ( event ){
event . preventDefault (); // 브라우저가 기본 동작을 실행하지 못하게 막기 // event object는 preventDefault함수를 기본적으로 갖고 있음
const usernameThatTheUserWrote = loginInput . value ;
localStorage . setItem ( USERNAME_KEY , usernameThatTheUserWrote );
loginForm . classList . add ( HIDDEN_CLASSNAME );
// greeting.innerText = "Hello " + username;
// 아래로 축약할수 있음 / ${}는 변수를 표현하는 방법
paintGreetings ( usernameThatTheUserWrote );
}
const savedUsername = localStorage . getItem ( USERNAME_KEY );
console . log ( savedUsername );
if ( savedUsername === null ) {
// show the form
loginForm . classList . remove ( HIDDEN_CLASSNAME );
loginForm . addEventListener ( "submit" , onLoginSubmit );
} else {
// show the greetings
paintGreetings ( savedUsername );
}
Clock.js ( 시계 )
const clock = document . querySelector ( "#clock" );
function getClock (){
const date = new Date ();
const hours = String ( date . getHours ()). padStart ( 2 , "0" );
const minutes = String ( date . getMinutes ()). padStart ( 2 , "0" );
const seconds = String ( date . getSeconds ()). padStart ( 2 , "0" );
clock . innerText = ` ${ hours } : ${ minutes } : ${ seconds } `
// clock.innerText = (`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`);
// 2자리 이하인 숫자앞에 0을 붙이기위하여 위와같이 코드수정
// String을 사용하는 이유 : padStart는 문자열의 시작을 다른 문자로 채워주는 함수이기 때문.
};
String ( new Date (). getHours ());
getClock ();
setInterval ( getClock , 1000 );
quotes.js (새로고침 시 명언 변경 )
const quotes = [
{
quote : "I don’t want to survive. Want to live the life I want." ,
korean : "밥만 먹고서 살아가고 싶지는 않아. 나는 내가 원하는 삶을 살고 싶다." ,
},
{
quote : "Be true to thyself." ,
korean : "자기 자신에게 솔직해져라" ,
},
{
quote : "It hurt because it mattered." ,
korean : "중요했기 때문에 아팠습니다." ,
},
{
quote : "No one is you and that is your power." ,
korean : "아무도 당신이 될 수 없다. 그것이 당신의 힘이다." ,
},
{
quote : "The more I get to know people, the more I find myself loving dogs." ,
korean : "사람에 대해 알면 알수록, 더 강아지를 사랑하게 된다." ,
},
{
quote : "A day without laughter is a day wasted." ,
korean : "웃음 없는 하루는 낭비한 하루다." ,
},
{
quote : "Success doesn't come overnight." ,
korean : "성공은 하룻밤 사이에 오지 않는다." ,
},
{
quote : "When they go low, we go high" ,
korean : "그들이 저급해도 우리는 품위 있게 갑시다." ,
},
{
quote : "I don't want a perfect life, I want a happy life." ,
korean : "완벽한 인생을 원하지 않고 행복한 삶을 원합니다." ,
},
{
quote : "Never speak bad about yourself" ,
korean : "스스로에 대해 안좋은 얘기 하지 말자." ,
},
]
// 명언 배열 저장
const quote_en = document . querySelector ( ".quoteBox .quote_en" );
const quote_ko = document . querySelector ( ".quoteBox .quote_ko" );
const todaysQuote = quotes [ Math . floor ( Math . random () * quotes . length )];
// Math.random()으로 무작위 난수를 추출 * quotes.length로 배열의 개수를 곱한 후 floor로 내림 -> 정수가 반환 되는데, 나의 배열 개수 이하의 숫자만 도출된다.
quote_en . innerText = todaysQuote . quote ;
quote_ko . innerText = todaysQuote . korean ;
// console.log(quote[0]);를 확인 해 보면 array가 나타나는데, 그 중 quote, korean이 필요 하므로 console.log(quote[0].quote);를 해보면 영어 명언만, korean을 대입하면 한국어 명언만 표시
// round(반올림) / ceil(올림) / floor (내림)
Background.js ( 새로고침 시 배경이미지 변경 )
const images = [
"bg01.jpg" ,
"bg02.jpg" ,
"bg03.jpg"
];
const chosenImage = [ images [ Math . floor ( Math . random () * images . length )]];
// console.log(chosenImage);
const bgImage = document . createElement ( "img" );
bgImage . src = `img/ ${ chosenImage } ` ;
document . body . appendChild ( bgImage );
// document.body.prepend(bgImage);
bgImage . id = 'bgImage' ;
// quotes 응용
이미지와 명연은 새로고침 시 마다 랜덤으로 바뀝니다.
그러므로, 방금 봤던 이미지 / 명언이 똑같이 다시 나올 수 있다는 의미이죠.
아직은 초급 강의이니.. 방금 나왔던 것을 제외하는 방법은 추후에 알게되면 포스팅 하겠습니다.
todo.js ( 일정 등록 / 삭제 )
const toDoForm = document . querySelector ( "#todo-form" );
const toDoList = document . querySelector ( "#todo-list" );
const toDoInput = document . querySelector ( "#todo-form input" );
let toDos = [];
// toDos는 사용자가 작성 시 매번 변경되므로 let
const TODOS_KEY = "todos" ;
function saveTodos (){
localStorage . setItem ( TODOS_KEY , JSON . stringify ( toDos ));
}
// JSON.stringify() == 문자로 저장
function sexyFilter ( toDo ){
return toDo . id !== parseInt ( li . id );
// toDo.id 와 parseInt(li.id)가 같지 않으면, true를 반환해야 함.
// toDo.id는 number타입, console.log(typeof li.id);로 확인해볼 수 있는데, li.id는 문자열 이므로 값이 일치할 수가 없음. parseInt를 통해 문자열을 숫자로 반환하면 해결됨.
}
// [1,2,3,4].filter(sexyFilter);
// filter는 foreach와 비슷하게 반복하는데, 즉 sexyFilter(1), sexyFilter(2), sexyFilter(3), sexyFilter(4)가 실해된다. true라면 유지하고, flase라면 제외될 것.
function deleteTodo ( event ){
const li = event . target . parentElement ;
// Button의 부모, 즉 li
li . remove ();
// toDos = toDos.filter(toDo => toDo.id !== parseInt(li.id));
// 위가 코드가 더 짧고 좋음. 공부용으로 function사용
toDos = toDos . filter ( sexyFilter );
// localStorage에서도 제거해야 새로고침 시 적용이 되므로, 해당 filter의 id와, li의 id가 일치하는 경우 제거.
saveTodos ();
}
function paintToDo ( newTodo ){
const li = document . createElement ( "li" );
li . id = newTodo . id ;
// 하단의 newTodoObj id:Date.now()를 통한 랜덤 id 부여, 하지만 완벽한 랜덤은 아니라고 함.
const span = document . createElement ( "span" );
const button = document . createElement ( "button" );
li . appendChild ( span );
li . appendChild ( button );
span . innerText = newTodo . text ;
button . innerText = "X" ;
toDoList . appendChild ( li );
// ul에 li추가
button . addEventListener ( "click" , deleteTodo );
}
function handleToDoSubmit ( event ){
event . preventDefault ();
const newTodo = toDoInput . value ;
// 사용자가 입력한 값
toDoInput . value = "" ;
const newTodoObj = {
text : newTodo ,
id : Date . now (),
// 추가되는 li에 랜덤 id를 부여하기 위함.
};
toDos . push ( newTodoObj );
paintToDo ( newTodoObj );
saveTodos ();
}
toDoForm . addEventListener ( "submit" , handleToDoSubmit );
const savedTodos = localStorage . getItem ( TODOS_KEY );
if ( savedTodos !== null ){
const parsedToDos = JSON . parse ( savedTodos );
// JSON.parse는 단순한 string을 array로 변경하기 위한 함수이다.
toDos = parsedToDos ;
// JSON.parse = 문자로 나열된 항목을 array로 변경시켜주는 함수 (이것을 실행시키기 전에 JSON.stringify를 실행하여 문자로 저장하여야 함)
parsedToDos . forEach ( paintToDo );
// forEach = parsedToDos 배열의 요소마다 paintToDo를 실행 ( 반복 )
}
weather.js ( 사용자의 위치를 통한 날씨 앱 )
const API_KEY = "openweathermap 에서 받은 key" ;
function onGeoOk ( position ){
const lat = position . coords . latitude ;
const lng = position . coords . longitude ;
fetch ( url ). then ( response => response . json (). then ( data => {
const weatherContainer = document . querySelector ( "#weather .weather_weather" );
const City = document . querySelector ( "#weather .weather_place" );
City . innerText = data . name ;
weatherContainer . innerText = ` ${ data . weather [ 0 ]. main } / ${ data . main . temp } ` ;
}));
}
function onGeoError (){
alert ( "Can't find you. No weather for you." );
}
navigator . geolocation . getCurrentPosition ( onGeoOk , onGeoError );
// onGeoOK = 위치정보를 받는데 성공한 경우 (허용)
// onGeoError = 위치정보를 받는데 실패한 경우 (거부)
weather.js의 경우 navigator.geolocation.getCurrentPosition()을 이용해서 위도와 경도를 구한 후에, api를 통해서 위도와 경도에 따른 날씨 / 지역 / 온도를 알 수 있습니다. 하지만, 영어로 표기되는 부분이 있고 날씨를 아이콘으로 표시하는 방법 등은 추후에 공부를 마치고 api에 올릴 예정입니다.
제 화면에서는 이미 동의를 해버려서, 새로고침을 해도 자동으로 날씨가 뜨는 바람에 강의 화면을 이용 했습니다.
어찌됐든, navigator를 이용해서 위도,경도를 알기 위해서는 사용자가 '동의'를 해야 합니다.
https://openweathermap.org/api
Weather API - OpenWeatherMap
Please, sign up to use our fast and easy-to-work weather APIs for free. In case your requirements go beyond our freemium account conditions, you may check the entire list of our subscription plans. You can read the How to Start guide and enjoy using our po
openweathermap.org
접속하셔서 회원가입 / 로그인 하신 후 오른쪽 상단 클릭 -> ~~Key 누르시면 키를 발급 받을 수 있습니다.
감사합니다~!
댓글