저번에 자바스크립트로 구현한 움직이는 글자에 이어 이번에는 랜덤숫자와 랜덤색을 구현하는 미니 과제를 받아서 풀어보았다.
초기 화면은 아래와 같이 세 개의 버튼이 있다.
버튼을 각각 누를 때마다 배경색이 랜덤하게 바뀐다.
이때 배경색이 어두우면 글자색은 흰색, 배경색이 밝으면 글자색은 검정색으로 설정된다.
버튼을 각각 누를 때마다 점수도 바뀌는데, 세 개의 버튼은 100, 200, 300 중 하나의 값을 가진다.
눌린 버튼이 가지는 랜덤값이 버튼을 누를 때마다 화면에 표시된다.
버튼을 누를 때마다 매번 랜덤하게 바뀌는 값이 누적값으로 쌓여 화면에 표시된다.
UI는 아래와 같이 주어진다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@unocss/reset/tailwind.min.css"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div class="my-5 flex justify-evenly">
<button id="btn-first" class="p-8 rounded-lg bg-red-300 text-xl">
1
</button>
<button id="btn-second" class="p-8 rounded-lg bg-green-300 text-xl">
2
</button>
<button id="btn-third" class="p-8 rounded-lg bg-blue-300 text-xl">
3
</button>
</div>
<p class="mx-auto w-fit my-4">+ <span id="showScore">0</span>점</p>
<p class="mx-auto w-fit my-4"><span id="score">0</span>점</p>
<script src="https://cdn.jsdelivr.net/npm/@unocss/runtime"></script>
<script type="module" src="./main.js"></script>
</body>
</html>
3개의 버튼을 const buttons로 선언하여 만든다.
const buttons = [
{
el: document.getElementById('btn-first'),
score: 0,
},
{
el: document.getElementById('btn-second'),
score: 0,
},
{
el: document.getElementById('btn-third'),
score: 0,
}
]
눌린 버튼의 점수를 나타내는 scoreEL과 점수의 누적값을 나타내는 showScoreEl을 선언하여 getElementById로 가져온다. 누적될 값인 score는 0으로 초기화해준다.
const scoreEl = document.getElementById('score');
const showScoreEl = document.getElementById('showScore');
let score = 0;
버튼을 눌렀을 때 점수와 배경색, 글자색 등이 랜덤하게 섞여야 한다. 그렇다면 일단 '버튼이 눌렸을 때'를 감지해야 한다. addEventListener을 사용하여 버튼 클릭에 반응해보자.
버튼 하나가 클릭되면('click') 누적 값인 score는 각 버튼의 score를 더하여 계산한다.
그리고 바뀐 값을 화면에 적용하기 위해 textContent를 사용했다.
마지막으로 랜덤하게 점수를 섞는 shuffleScore와 랜덤하게 배경색/글자색을 섞는 shuffleColors 함수를 만들어 호출한다.
for (const button of buttons) {
button.el.addEventListener('click', () => {
score += button.score;
// 바뀐 값 화면에 적용하기
scoreEl.textContent = score;
showScoreEl.textContent = button.score;
// 값 바꾸기
shuffleScores();
shuffleColors();
});
}
일단 각 버튼은 100, 200, 300 중 하나의 값을 가질 것이므로 이 세 숫자가 들어간 배열인 array를 만든다.
그리고, 이를 정렬하기 위해 ranNum을 쓰는데, ranNum은 0부터 1까지의 랜덤값을 뽑는 Math.random()에서 0.5를 빼서 양수와 음수가 골고루 나오게 하는 함수이다.
이 ranNum을 sort() 안에 넣어주면 랜덤하게 정렬이 된다.
function shuffleScores() {
const ranNum = () => Math.random() - 0.5;
const array = [100, 200, 300];
const shuffled = [...array].sort(ranNum);
buttons[0].score = shuffled[0];
buttons[1].score = shuffled[1];
buttons[2].score = shuffled[2];
}
어떤 부분이 이해가 안 되냐면, ranNum은 0 or 양수 or 음수를 반환할텐데, sort 안에 0/양수/음수가 들어가면 오름차순, 내림차순 등으로 정렬이 되어야 하는 거 아닌가? 어떻게 console.log(shuffled)
를 찍어봤을 때 [200, 100, 300]과 같은 정렬되지 않은 값이 나올 수 있지??
👉 답!
일단 sort는 첫번째 인자로 두 수 a, b를 받아서 양수/0/음수 중 하나를 반환하는 함수를 받는다.
"a < b" => "a - b < 0"
"a = b" => "a - b = 0"
"a > b" => "a - b > 0"
따라서 a-b가 양수/0/음수인지를 보면 대소비교를 할 수 있다.
하지만!! 위에서는 a, b와 무관하게 Math.random() - 0.5를 활용해서 [-0.5, 0.5] 구간 안의 아무 값이나 반환하고 있다.
sort를 끝까지 하려면 여러번 함수를 호출해서 각 값을 비교해야 하는데, Math.random()의 특성상 호출마다 값이 바뀌어서 결국 뒤죽박죽인 순서로 정렬이 되게 된다.
버튼을 클릭할 때마다 버튼들의 색이 랜덤하게 바뀌도록 해보자. rgb를 사용했는데, rgb란 빛의 삼원색을 이용하여 색을 표현하는 방식으로 빨강(RED), 초록(GREEN), 파랑(BLUE) 색으로 이루어져 있다.
빨강, 초록, 파랑을 각각 변수로 만들어 랜덤한 값을 뽑고, 이들을 합쳐 rgb로 색을 나타낼 것이다. (템플릿 리터럴을 사용해 합쳐주었다.) 그리고 배경색이 255의 절반인 128보다 크면(밝으면) 글자색은 흰색, 128보다 작으면(어두우면) 글자색은 검정색으로 설정되게 하였다.
function shuffleColors() {
// 구조분해할당. el만 빼올 수 있음
for (const { el } of buttons) {
const red = Math.round(Math.random() * 255);
const green = Math.round(Math.random() * 255);
const blue = Math.round(Math.random() * 255);
if (Math.floor((red + green + blue) / 3) > 128) {
el.style.color = 'black';
} else {
el.style.color = 'white';
}
el.style.backgroundColor = `rgb(${red}, ${green}, ${blue})`;
}
}
완성했다!!!
바닐라 자바스크립트로 간단한 과제를 풀어보았다.(생각보다 그렇게,, 간단하지는 않았던 것 같다😂) 그래도 검색하고 질문해가며 색을 랜덤하게 어떻게 바꾸는지, 글자색 다크모드는 어떻게 구현해야 하는지를 알 수 있었다.
무엇보다, 아래와 같은 코드가 신기했다. 각 버튼이 클릭되면 shuffle 함수를 실행시켜야 했는데, 이렇게 for문으로 각 button의 dom요소에 접근하는 방식을 새로 알게 되었다.
for (const button of buttons) {
button.el.addEventListener('click', () => {
})
}
그리고, 완성된 코드를 따라서 칠 때는 잘 몰랐는데 내가 hard training이라고 부르는 안보고 다시 구현해보기를 하며 안다고 생각했던 많은 것들을 사실 모르고 있었다는 것을 알게 되었다. 앞으로도 간단한 걸 구현한다고 해도 혼자서 다시 구현해보는 연습을 꾸준히 해야겠다고 생각했다.