<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="css/style.css" />
<title>Momentum App</title>
</head>
<body>
<h2 id="clock">00:00</h2>
<!-- 정규식 넣어보기.... but 최근의 로그인 시스템은 토큰으로 구글로그인, 네이버로그인, 카톡로그인을 사용한다....... -->
<form class="hidden" id="login-form">
<input
type="text"
required
maxlength="15"
placeholder="what is your name?"
/>
<!-- input태그로 submit가 발동될때 새로고침후 form을 submit하도록 브라우저에 프로그래밍되어있다. -->
<input type="submit" value="Log-In" />
<!-- <button>Log in</button> -->
</form>
<!-- login After start -->
<h1 class="hidden" id="greeting"></h1>
<button class="hidden" id="logout">Log-Out</button>
<form id="todo-form">
<input
type="text"
placeholder="할일 목록을 작성하신 후 엔터를 입력해주세요"
required
/>
</form>
<ul id="todo-list"></ul>
<!-- login After end -->
<!-- 명언 start -->
<div id="quotes">
<span></span>
<span></span>
</div>
<!-- 명언 end -->
<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>
</body>
</html>
clock.js
const clock = document.querySelector('h2#clock')
//clock.innerText = 'clock'
// 출력시 렌덤으로 색상 변경
function getRandomColor() {
const letters = '0123456789ABCDEF'
let color = '#'
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)]
}
return color
}
// padStart(n,'String') 문자열 길이가 n까지잡고 문자열 길이가 n이 아니면 앞에 string문자열을 추가해준다. 01 02 03 04 05
// padEnd(n,'String') 문자열 길이가 n까지잡고 문자열 길이가 n이 아니면 뒤에 string문자열을 추가해준다. 10 20 30 40 50
// 사용시 **String으로 형변환
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')
//console.log(`${date.getHours()} : ${date.getMinutes()} :${date.getSeconds()}`)
const randomColor = getRandomColor()
clock.style.color = randomColor
clock.innerText = `${hours} : ${minutes} :${seconds}`
//clock.innerText = hour + ':' + minute + ':' + seconds.padStart(2, '0')
}
// 먼저 시작해주어야지 바로 실행(출력)된다
getClock()
// 반복해서 화면에 출력해주는 setInterval 매개변수는 2개 하나는 출력하려는 함수, 하나는 시간(간격) 밀리세컨드
setInterval(getClock, 1000)
// 설정한 시간에 한번 출력 setTimeout 매개변수는 2개 하나는 출력하려는 함수, 하나는 시간 밀리세컨드
//setTimeout(sayHello, 5000)
quote.js
// 2023.08.30 배열에 객체를 넣었다.
const quotes = [
{
quote: '소크라테스 (Socrates)',
author: '지혜는 자신의 무지를 아는 것이다.',
},
{
quote: '아리스토텔레스 (Aristotle)',
author:
'우리를 반복하는 것이 덕을 만든다. 그러므로 우리는 행동하는 것이 아니라 행동이 우리를 만든다.',
},
{
quote: '에피쿠로스 (Epicurus)',
author: '불행은 결코 그릇이 아니라, 태도에서 비롯된다.',
},
{
quote: '칸트 (Immanuel Kant)',
author:
'두 가지 것은 나로 하여금 놀랍게도 본질적으로 경외감을 느끼게 한다. 밤 하늘 위의 별과, 인간의 도덕적 의무.',
},
{
quote: '니체 (Friedrich Nietzsche)',
author: '그대가 목적을 갖고 있다면 그대는 거의 모든 수단을 갖게 된다.',
},
{
quote: '산티아고 라모스 (Santayana)',
author: '과거를 기억하지 못하는 사람들은 그 과거를 되풀이한다.',
},
{
quote: '알베르 카뮈 (Albert Camus)',
author: '인생은 야심과 무미건조함 사이에서의 균형을 찾는 것이다.',
},
{
quote: '한나 아렌트 (Hannah Arendt)',
author: '생각하는 법을 배우는 것은 모든 교육의 가장 중요한 목표이다.',
},
{
quote: '칼 포퍼 (Karl Popper)',
author:
'진리를 찾으려고 시도하는 과정에서 오류를 범하는 것은 단지 지식의 증가이다.',
},
{
quote: '존 로크 (John Locke)',
author:
'우리는 모든 것을 타고난 상태에서 받아들이며, 인간의 지식과 행동은 경험을 통해 형성된다.',
},
]
const quote = document.querySelector('#quotes span:first-child')
const author = document.querySelector('#quotes span:last-child')
//console.log(quotes[0])
// Math.random() : 0~1사이의 숫자를 무작위로 출력해준다. 따라서 내가 출력하고 싶은 갯수중에서 랜덤으로 출력하려면
// 내가 출력하고 있는 갯수를 곱해주어야한다.
//Math.round() : 반올림
//Math.ceil() : 올림
//Math.floor() : 버림
//console.log(parseInt(Math.random() * quotes.length))
//parseInt()를 사용하여 아래와 같이 실수의 Number나 String 객체를 정수로 변환할 수 있다.
// 변환된 타입은 모두 Number입니다.
// quotes의 배열 순서 랜덤이 소수점이라서 정수로 변환
//const quotesSeq = Math.floor(Math.random() * quotes.length) --> 이렇게 사용 할 수도 있고(버림)
const quotesSeq = parseInt(Math.random() * quotes.length) // --> 이렇게 사용 할 수도 있다.
const todayQuote = quotes[quotesSeq]
const printQuote = todayQuote.author
const printAuthor = todayQuote.quote
console.log(quotesSeq)
console.log(quotes[quotesSeq].author)
console.log(quotes[quotesSeq].quote)
quote.innerText = printQuote
author.innerText = printAuthor
background.js
// ** 이미지 경로 아니다. 하드코딩으로 이미지이름을 입력해준것일 뿐이다. String이다.
const images = [
'gautier-salles.jpg',
'jurre-houtkamp.jpg',
'reuben-mcfeeters.jpg',
]
const todayImgSeq = Math.floor(Math.random() * images.length)
const todayImg = images[todayImgSeq]
console.log(todayImg)
// document.createElement() 태그를 생성하는 부분
const bgImg = document.createElement('img')
// 여기서 진짜 경로가 추가된다.
bgImg.src = `img/${todayImg}`
console.log(bgImg)
// body 태그 내 마지막에 img태그 추가
document.body.appendChild(bgImg)
// body 태그 내 첫번째에 img태그 추가
//document.body.prependChild(bgImg)
todo.js
// 2023.08.30 / SaGo_Muncci / todo이게 momentum의 핵심기능이다. 중요!
// client에서는 화면을 기능(보여줄것,디자인)별로 부분 부분으로 나누고 뼈대를 세운다.(html)
// 부분마다 필요한 기능 및 데이터를 js로 개발한다.
// 작성한 뼈대 및 위치 조정, 디자인은 css로 한다.
// 지금 클라이언트단에서는 이렇게 받지만 todolist에 있는 데이터를 서버로 넘겨서 저장하고 출력해내야한다.
// client에서 입력하면 api로 서버에 맞게 컨트롤러에 접근하고 서비스타고 디비에 저장
const toDoForm = document.querySelector('#todo-form')
const toDoInput = toDoForm.querySelector('input')
const toDoList = document.querySelector('#todo-list')
const TODOS_KEY = 'todos'
// 이렇게 하면 새로고침 할때마다 todos의 값은 빈값으로 시작한다. 그러나 localStorage에는 저장되어있다.
// 보이는것만 새로고침해서 빈 배열로 보이는 것이다.
//const todos = []
// 따라서 변수를 재할당 할수 있는 let으로 변경하자.
let todos = []
function paintToDo(newTodo) {
const liTodo = document.createElement('li')
const spanTodo = document.createElement('span')
spanTodo.innerText = newTodo
const toDoBtn = document.createElement('button')
toDoBtn.innerText = '✖'
toDoBtn.addEventListener('click', deleteToDo)
console.log(spanTodo)
toDoList.appendChild(liTodo)
liTodo.appendChild(spanTodo)
liTodo.appendChild(toDoBtn)
}
// **중요
// 나도 어떤 버튼을 누르는지 구분자가 필요하다고 생각했다.
// 내가 생각했던 방법은 클릭이벤트에 매개변수로 해당 클릭버튼의 부모 li태그 전체를 넘겨서
// 메서드에서 remove() 삭제함.
// handleToDoList의 매개변수인 event를 사용하는 방법이.. 생각도 못했다.
function deleteToDo(event) {
//const btnParent = toDoBtn.parentElement
console.log(event.target)
console.dir(event.target.parentElement.innerText)
const rmBtnPerntLi = event.target.parentElement
rmBtnPerntLi.remove()
}
function saveTodo() {
//아래 코드는 문제점이있다. 로컬스토리지에 저장될때
//배열로 저장되지 못하고 일반적인 텍스트 형태로 저장된다 --> '1,2,3,4'
//localStorage.setItem('todos', todos)
//JSON.stringify() : 어떤것이든 string으로 바꿔주는 기능이다.
// 배열 형식으로 저장가능하다. --> '["1","2","3","4"]' 스트링이지만 이렇게 출력함 배열형식으로
localStorage.setItem(TODOS_KEY, JSON.stringify(todos))
}
function handleToDoList(event) {
event.preventDefault()
const newTodo = toDoInput.value
console.log(newTodo)
todos.push(newTodo)
toDoInput.value = ''
saveTodo()
paintToDo(newTodo)
}
toDoForm.addEventListener('submit', handleToDoList) // --> sub밋을 눌러야 작동 새로고침하면 안탄다.
// **event와 마찬가지로, js에서 item은 parsedTodos 배열의 item을 가리킨다.
function sayhello(item) {
console.log('itemSeq', item)
}
// 새로고침 하면 이것 부터 탄다
const saveTodos = localStorage.getItem(TODOS_KEY)
console.log(saveTodos)
if (saveTodos !== null) {
const parsedTodos = JSON.parse(saveTodos)
console.log(parsedTodos)
// 이전에 저장되어있던것을 변수(let todos)에 재할당해주자.
todos = parsedTodos
/* 중요 */
//parsedTodos.forEach((item) => console.log('itemSeq', item)) //--> 이것과
parsedTodos.forEach(paintToDo) //--> foreach 이것과
// 이것은 같다
// for (let index = 0; index < parsedTodos.length; index++) {
// const element = parsedTodos[index]
// paintToDo(element)
// }
}
// 내생각 대로 짜본것
//let toDoSeq = 0
// function paintToDo(newTodo) {
// const liTodo = document.createElement('li')
// const spanTodo = document.createElement('span')
// const toDoBtn = document.createElement('button')
// toDoBtn.innerText = '✖'
// spanTodo.innerText = newTodo
// console.log(spanTodo)
// toDoList.appendChild(liTodo)
// toDoSeq++
// liTodo.setAttribute('id', 'todolist' + toDoSeq)
// liTodo.appendChild(spanTodo)
// liTodo.appendChild(toDoBtn)
// toDoBtn.addEventListener('click', function () {
// const btnParent = toDoBtn.parentElement
// console.log(btnParent)
// deleteToDo(btnParent)
// })
// }
// function deleteToDo(btnParent) {
// console.log(btnParent.id)
// //document.removeElement('#' + btnParent.id)
// btnParent.remove()
// }
배운점
무엇보다 어떤 어플리케이션을 만드는지 설계가 굉장히 중요하다는것을 다시한번 깨달았다.
중간 중간에 강의 듣기전 나혼자서 다음 강의의 내용을 유추해서 나름 코딩을 했지만 삼천포로 빠지는 경우가 많았다. 그때마다 지금 하고 있는 앱의 특성을 상기후 바로 잡을 수 있었다.
또한 todo.js 상단에 주석해놓은것과 설계시 마찬가지로 화면을 나누어 디자인및 기능을 정한 후 html 뼈대를 세우고 각 html에 맞게 데이터를 출력하는 기능은 js 이후 기능이 완성되었으면 css로 다듬는 것이 한사이클이라는 것을 알게되었다.