• Number Baseball, 숫자 야구

 숫자 야구란, 랜덤한 세 자리 숫자가 주어지면 그 숫자가 무엇인지 맞혀보는 게임이다. 숫자와 숫자가 위치한 자리까지 일치하면 Strike, 자리는 일치하지 않으나 포함되어 있으면 Ball로 처리된다. 예를 들면, 랜덤한 숫자가 375이고 내가 745라고 예상했다면 7은 자리는 일치하지 않으나 포함되어 있으나 1 Ball로 처리되고, 4는 아예 포함되어 있지 않으니 Strike나 Ball 둘다 아니다. 5는 숫자와 자리까지 일치하니 1 Strike가 된다.

 

 숫자 야구에 대한 자세한 설명 : https://namu.wiki/w/%EC%88%AB%EC%9E%90%EC%95%BC%EA%B5%AC

 

 크게 막히는 부분은 없었다. 비효율적일 순 있으나 내가 설계한 대로 동작이 잘되니 뿌듯하다. 중간 중간에 구글링으로 필요한 것을 찾아내는 방법도 어느 정도 익혀가는 것 같다. 특히 MDN을 되도록이면 참고하려고 했다. 1차적인 자료를 읽어서 제대로 이해하고 써먹는 것이 나중에 응용하는 데에 있어 좋을 것이라 생각했기 때문이다. 뭐든 뿌리를 알아야 되지 않을까!

 

  • HTML
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <link
      href="https://fonts.googleapis.com/css?family=Pacifico&display=swap"
      rel="stylesheet"
    />
    <link
      href="https://fonts.googleapis.com/css?family=Varela+Round&display=swap"
      rel="stylesheet"
    />
    <link rel="icon" href="/images/favicon.ico" />
    <link rel="stylesheet" type="text/css" href="style.css" />
    <title>Baseball Project</title>
  </head>

  <body>
    <section>
      <div class="image-box">
        <img src="images/vanilla_coding_logo.png" />
      </div>
      <h1>Baseball</h1>

      <!-- 야구게임 Start -->

      <div class="contents">
        <div class="clickButton">
          <button id="startButton">Start</button>
          <button id="restartButton">Restart</button>
        </div>
        <br />
        <div class="notificationBox">
          <p id="notice">[Notice!]</p>
          <ul>
            <li><p>Press the start button at first</p></li>
            <li><p>Please enter only number</p></li>
            <li><p>Don't enter duplicate number</p></li>
          </ul>
        </div>
        <div id="numberBox"></div>
        <div class="strikeBall">
          <div id="strike">Strike</div>
          <div id="ball">Ball</div>
          <div id="chance"></div>
        </div>
        <input
          type="number"
          id="inputNumber"
          oninput="handleOnInput(this, 3)"
          placeholder="What is your number?"
        />
      </div>

      <!-- 야구게임 End -->
    </section>

    <script src="index.js"></script>
  </body>
</html>
  • CSS
body {
  background-image: url("./images/bg.jpeg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  font-family: "Varela Round", sans-serif;
}

.image-box {
  display: flex;
  justify-content: center;
  align-items: center;
}

img {
  width: 700px;
  height: 200px;
}

h1 {
  font-family: "Pacifico", cursive;
  text-align: center;
  font-size: 36px;
}

.contents {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.notificationBox {
  padding: 15px;
  border: 3px solid black;
  border-radius: 5px;
  background-color: white;
  font-size: 20px;
  font-weight: 300;
  color: black;
}

#notice {
  padding-top: 0px;
  text-align: center;
  font-size: 25px;
  font-weight: 900;
}

#numberBox {
  margin-top: 30px;
  width: 400px;
  height: 200px;
  border: 3px solid black;
  border-radius: 3px;
  background-color: yellow;
  display: flex;
  text-align: center;
  justify-content: center;
  flex-direction: column;
  font-size: 50px;
}

.strikeBall {
  margin-top: 20px;
  display: flex;
  width: 200px;
  height: 25px;
  border: 3px solid black;
  border-radius: 3px;
  background-color: rgb(20, 207, 231);
  justify-content: center;
}

#strike {
  margin-top: 2px;
  margin-right: 30px;
}

#ball {
  margin-top: 2px;
  margin-right: 30px;
}

#chance {
  margin-top: 2px;
}

#inputNumber {
  margin-top: 20px;
  margin-bottom: 20px;
}
  • JavaScript
var numberArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
var startButton = document.querySelector("#startButton");
var restartButton = document.querySelector("#restartButton");
var inputNumber = document.querySelector("#inputNumber");
var numberBox = document.querySelector("#numberBox");
var strikeNumber = document.querySelector("#strike");
var ballNumber = document.querySelector("#ball");
var chance = document.querySelector("#chance");
let randomArray = [];
let chanceNumber = 10;
chance.textContent = chanceNumber;

inputNumber.style.display = "none";

restartButton.addEventListener("click", function reload() {
  location.reload();
});

startButton.addEventListener("click", function createNumber() {
  inputNumber.style.display = "";
  startButton.remove();
  numberBox.textContent = "? ? ?";

  for (var i = 0; i < 3; i++) {
    var randomIndex = Math.floor(Math.random() * numberArray.length);
    var randomValue = numberArray[randomIndex];
    numberArray.splice(randomIndex, 1);
    randomArray.push(randomValue);
  }

  alert("Here is a new number. Guess what it is!");
  console.log(randomArray);
});

function handleOnInput(el, maxlength) {
  if (el.value.length > maxlength) {
    el.value = el.value.substr(0, maxlength);
  }
}

inputNumber.addEventListener("keypress", function (key) {
  if (key.key === "Enter") {
    var inputValue = inputNumber.value;
    var inputValueArray = Array.from(inputValue);
    console.log(inputValueArray);

    if (inputValueArray.length < 3) {
      alert("Please enter 3 digit number");
      return;
    }

    var strike = 0;
    var ballcount = 0;

    for (var i = 0; i < 3; i++) {
      if (inputValueArray[i] === randomArray[i]) {
        strike += 1;
      }
      if (randomArray.indexOf(inputValueArray[i]) >= 0) {
        ballcount++;
      }
    }

    var ball = ballcount - strike;

    if (ball < 0) {
      ball = 0;
    }

    strikeNumber.textContent = strike + "S";
    ballNumber.textContent = ball + "B";

    console.log("strike : " + strike);
    console.log("ball : " + ball);

    if (strike === 3) {
      numberBox.textContent = randomArray.join("");
      alert(`YES! That's right!`);
    }

    chanceNumber = chanceNumber - 1;
    chance.textContent = chanceNumber;

    if (chanceNumber === 0) {
      alert("Over! Please click restart button");
      inputNumber.remove();
    }
  }
});

 HTML과 CSS에서는 그저 배웠던 것들을 적용하면 되었기 때문에 크게 문제가 되는 건 없었다. JavaScript를 짤 때 몇 가지 문제에 직면해 애를 먹었다. 그 문제와 해결은 다음과 같이 했다.

 

 0. 숫자 비교 등은 어떻게 할 것인가!

 -> 일단 배열 형태로 랜덤한 숫자가 생성되게 하고, 유저가 입력하는 숫자도 Array.from으로 배열로 바뀌게 했다. 그 후 for문을 사용해 랜덤 숫자와 유저의 숫자를 비교했고 일치하면 strike의 숫자가 올라가게 했다. ball은 indexOf를 사용해서 count했다. 해당 숫자가 랜덤 숫자(randomArray)중에 존재하기만 해도 1이 올라간다.(ballcount++)

 

 0-1. 이 때 문제가 생기는 것은 ball이다.

 -> 랜덤한 숫자가 375이고 유저의 예상 숫자가 357이라면 strike는 정상적으로 1이 뜨나 ball은 3이 떠버린다. 1strike 2ball이 떠야되기 때문에 이는 잘못된 것이다. 하지만 간단하다. ball - strike해주면 된다 ^.^ ball - strike이 진짜 ball이기 때문에 앞의 ball은 ballcount로 만들었다.

 

 1. 세 자리가 중복되지 않으면서 랜덤한 숫자 생성

 -> 랜덤한 세 자리 숫자 생성을 위해 Math.floor와 Math.random을 사용했고, 중복되지 않도록 한 번 뽑힌 숫자는 splice로 제거 했다.

 

 2. 3자리 숫자만 입력하게 하기

 -> input의 type이 number일 때는 maxlength와 minlength가 안먹힌다. 그래서 handleOnInput을 사용해주었고 입력받은 숫자가 3자리 미만일 때는 곧바로 return이 되어 inputNumber에 추가된 함수가 종료되도록 하고 alert창을 띄우게 했다.

 

 3. 여러번 start를 누를 경우, input에 여러번 입력할 경우 의도하지 않은 바가 나타난다.

 -> 위 설계는 여러번 start를 누른다고 계속해서 랜덤한 3자리 숫자가 나타나지 않는다... 그리고 start를 누르지 않았는데 input에 입력하면 10번의 chance가 입력할 때마다 감소한다. 이것들은 단순하게 때에 따라 display를 none하는 것을 이용했다. 

 

 

 

 

 다른 사람이 어떻게 작업했는지는 모르겠다. 당연히 나보다 잘했겠지... 일부러 안 찾아보고 되는 대로 raw하게 해보자 생각하며 시도했는데 좀 퀄리티가 처참한 것 같다 ㅎㅎㅎ

  • Koans

 JavaScript-Koans : https://github.com/mrdavidlaing/javascript-koans

 

 Koans는 선문답이라는 뜻이다. 그냥 먼저 묻고 답한다는 건가? ㅎㅎㅎ

 

 Github에서 남이 작성한 코드를 다운 받는 것도 처음이고, Readme를 읽는 것도 처음이었다. expect, it, describe를 본 적이 없으며 영어로 된 것들을 해석한다고 1문제부터 막혔었다. 진짜 쉬운 문제였는데...

 

 JavaScript의 문법에 대해 기초적인 것들을 다루는 문제였다. 사실 완전히 다 이해하진 못했지만 어느 정도 감을 익혔고 자신감이 붙었다. MDN도 진짜 많이 뒤져봤다.

 

이정도면 약과인가...?

 

 후에 JavaScript를 더 사용해보고 다시 풀어봐야 겠다.

 

맨 처음 화면이다.

 

하나하나씩 초록색으로 바뀌면서 성취감이 장난 아니다.

 위에 enlightenment라는 단어가 있는데 깨우침, 이해, ... 혹은 계몽?이라는 뜻이라고 한다. 다 맞췄다고 해서 깨우쳤다고 할 수 없을 것 같고, 응용할 수 있을 때 비로소 깨우쳤다고 말할 수 있을 것 같다. 헤헷

 대참사다. 2시간 정도만에 만들긴 했지만 중복이 엄청나다. 동작이 잘되고 나름 응용을 섞었기 때문에 보람차긴 하지만 for문을 이용했으면 상당히 압축되었을건데 아쉽다. 코딩 실력이 아직 거기까진 부족한 것 같다. 아무래도 JavaScript 기본서 책 1권이 필요하다는 생각이 들었다.

 

  • Carousel, 캐러셀

 Carousel은 회전목마 혹은 수하물 컨베이어 벨트를 뜻하는 단어이다. 둘의 공통점은 반복해서 돌아간다는 점이다. 웹에서 Carousel은 이미지 등의 컨텐츠를 노출시키기 위한 UI로 활용된다.

 

 1. 요구 사항

 위 UI를 봤을 때 우리는 직감하는 것이 몇 가지 있다. 왼쪽, 오른쪽 버튼을 누르면 흰색 네모 칸의 컨텐츠가 바뀔 것이고, 아래의 점들을 누르면 해당 점에 일치하는 컨텐츠로 흰색 네모 칸이 바뀔 거라는 것이다.

 

 2. 나의 풀이

 이번 퀴즈는 Boilerplate Code가 제공되어 해당 코드를 재활용했다.

 

 * Boilerplate Code란 여러 곳에서 재활용 될 수 있는, 반복적으로 비슷한 형태를 띄는 코드를 뜻한다. 1890년대 광고나 컬럼에 반복적으로 사용되는 텍스트를 찍어내기 위해 강철판에 텍스트를 새겨 인쇄를 했었는데, 이것이 어원이 되었다.

 

 - HTML

 

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://fonts.googleapis.com/css?family=Pacifico&display=swap"
      rel="stylesheet"
    />
    <link
      href="https://fonts.googleapis.com/css?family=Varela+Round&display=swap"
      rel="stylesheet"
    />
    <link rel="icon" href="/images/favicon.ico" />
    <link rel="stylesheet" type="text/css" href="style.css" />
    <title>Carousel Project</title>
  </head>

  <body>
    <section>
      <div class="image-box">
        <img id="logo" src="images/vanilla_coding_logo.png" />
      </div>
      <h1>Carousel</h1>
      <h1 class="nowNumber">Number : 1</h1>

      <!-- Carousel Start -->
      <div class="contents">
        <button id="left"></button>
        <img class="image1" id="vanilla" src="images/image-1.png" />
        <button id="right"></button>
      </div>

      <div class="dots">
        <button id="dot1"></button>
        <button id="dot2"></button>
        <button id="dot3"></button>
        <button id="dot4"></button>
        <button id="dot5"></button>
      </div>
      <!-- Carousel End -->
    </section>

    <script src="index.js"></script>
  </body>
</html>

 CSS, JavaScript는 모두 파일 형태로 불러오는 방식이 사용되었다. 그리고 nowNumber를 추가하여 현재 컨텐츠가 몇 번째 컨텐츠인지 알 수 있게 하였고 left와 rigth 버튼, 점 버튼들을 추가했다.

 

 - CSS

body {
  background-image: url("./images/bg.jpeg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  font-family: "Varela Round", sans-serif;
}

h1 {
  font-family: "Pacifico", cursive;
  text-align: center;
  font-size: 36px;
  margin: 0;
}

.image-box {
  text-align: center;
}

#logo {
  width: 800px;
}

.contents {
  display: flex;
  justify-content: center;
}

#left {
  border-radius: 100px;
  border: none;
  background-image: url("./images/left.png");
  background-position: center;
  background-size: cover;
  background-color: yellow;
  width: 50px;
  height: 50px;
  margin: auto;
}

#right {
  border-radius: 100px;
  border: none;
  background-image: url("./images/right.png");
  background-position: center;
  background-size: cover;
  background-color: yellow;
  width: 50px;
  height: 50px;
  margin: auto;
}

#vanilla {
  border-radius: 3px;
  border: 2px solid gray;
  background-position: center;
  background-size: cover;
  width: 400px;
  height: 400px;
}

.dots {
  display: flex;
  justify-content: center;
  margin-top: 30px;
}

#dot1,
#dot2,
#dot3,
#dot4,
#dot5 {
  margin-right: 20px;
  border: 1px solid black;
  border-radius: 100px;
  width: 10px;
  height: 15px;
  background-color: yellow;
}

 

 - JavaScript

var dot1 = document.querySelector("#dot1");
var dot2 = document.querySelector("#dot2");
var dot3 = document.querySelector("#dot3");
var dot4 = document.querySelector("#dot4");
var dot5 = document.querySelector("#dot5");

var img = document.querySelector("#vanilla");
var nowNumber = document.querySelector(".nowNumber");

dot1.addEventListener("click", function changeImage1() {
  img.setAttribute("src", "images/image-1.png");
  img.classList.remove("image1", "image2", "image3", "image4", "image5");
  img.classList.add("image1");
  nowNumber.textContent = "Number : 1";
});

dot2.addEventListener("click", function changeImage2() {
  img.setAttribute("src", "images/image-2.png");
  img.classList.remove("image1", "image2", "image3", "image4", "image5");
  img.classList.add("image2");
  nowNumber.textContent = "Number : 2";
});

dot3.addEventListener("click", function changeImage3() {
  img.setAttribute("src", "images/image-3.png");
  img.classList.remove("image1", "image2", "image3", "image4", "image5");
  img.classList.add("image3");
  nowNumber.textContent = "Number : 3";
});

dot4.addEventListener("click", function changeImage4() {
  img.setAttribute("src", "images/image-4.png");
  img.classList.remove("image1", "image2", "image3", "image4", "image5");
  img.classList.add("image4");
  nowNumber.textContent = "Number : 4";
});

dot5.addEventListener("click", function changeImage5() {
  img.setAttribute("src", "images/image-5.png");
  img.classList.remove("image1", "image2", "image3", "image4", "image5");
  img.classList.add("image5");
  nowNumber.textContent = "Number : 5";
});

var left = document.querySelector("#left");
var right = document.querySelector("#right");

left.addEventListener("click", function changeImageLeft() {
  if (img.className === "image1") {
    img.setAttribute("src", "images/image-5.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image5");
    nowNumber.textContent = "Number : 5";
  } else if (img.className === "image2") {
    img.setAttribute("src", "images/image-1.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image1");
    nowNumber.textContent = "Number : 1";
  } else if (img.className === "image3") {
    img.setAttribute("src", "images/image-2.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image2");
    nowNumber.textContent = "Number : 2";
  } else if (img.className === "image4") {
    img.setAttribute("src", "images/image-3.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image3");
    nowNumber.textContent = "Number : 3";
  } else if (img.className === "image5") {
    img.setAttribute("src", "images/image-4.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image4");
    nowNumber.textContent = "Number : 4";
  }
});

right.addEventListener("click", function changeImageRight() {
  if (img.className === "image1") {
    img.setAttribute("src", "images/image-2.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image2");
    nowNumber.textContent = "Number : 2";
  } else if (img.className === "image2") {
    img.setAttribute("src", "images/image-3.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image3");
    nowNumber.textContent = "Number : 3";
  } else if (img.className === "image3") {
    img.setAttribute("src", "images/image-4.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image4");
    nowNumber.textContent = "Number : 4";
  } else if (img.className === "image4") {
    img.setAttribute("src", "images/image-5.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image5");
    nowNumber.textContent = "Number : 5";
  } else if (img.className === "image5") {
    img.setAttribute("src", "images/image-1.png");
    img.classList.remove("image1", "image2", "image3", "image4", "image5");
    img.classList.add("image1");
    nowNumber.textContent = "Number : 1";
  }
});

완성된 화면

 

 먼저 점들을 클릭할 때 해당 class의 name들을 모두 지워버리고(remove) 점 순서에 따라 일치하는 이미지를 추가하고 class를 부여했다.(add)

 

 화살표를 누를 때는 현 화면이 1번째 였다면 왼쪽 클릭 시 5번째로, 2번째 였다면 1번째로 이동하게 하는 매커니즘을 구상했다. 이 때에도 점을 클릭했을 때와 마찬가지로 기존 class의 name들을 모두 지워버리고(remove) 이동했을 때 일치해야 하는 이미지를 추가하고 class를 부여했다.(add) 오른쪽과 똑같이 동작되도록 했다.

 

 추가로 현 이미지가 몇 번째 이미지인지 boiler plate에는 없어서 nowNumber.textContent를 추가해 몇 번째 이미지인지 인지할 수 있게 했다.

 

 

 

 그렇다. 이보다 비효율적일 수는 없다. for문을 활용하지 못하는 적절한 예시이다. 코드가 짧아서 다행이지만 길어지고 부하가 많아질수록 비효율성을 두드러지게 나타날 것이다.

 

 정상적으로 동작된다는 것에 만족하지만, 중복은 프로그래밍에서 상당한 비효율성을 불러온다. 책을 사든 구글링을 하든 문법을 좀 배워서 타개해봐야겠다.

  • Background Changer

 HEX Color Code란 RGB 방식의 '색상 코드' 표기법이다. #뒤에 여섯 자리의 글자가 오는데, 이는 0~9까지의 숫자 4개와 A~F까지의 알파벳 2개로 이루어져 있다. 예를 들면, #75E9A3, #F0C433 이런 것이다. 한 자리에  16가지가 들어갈 수 있으므로 16진수라고 보면 되겠다. 그렇다면 이런 헥스 코드로 만들 수 있는 색상의 수는 총 16^6으로 16,777,216개이다.

 

 1. 요구 사항

 - 위와 같은 UI를 만든다.

 - CLICK ME 버튼을 클릭 시 #3474FF(헥스 코드)가 랜덤하게 바뀐다.

 - CLICK ME 버튼을 클릭 시 헥스 코드가 바뀜과 동시에, 바뀐 헥스 코드에 일치하는 배경색으로 바뀐다.

 

 2. 나의 풀이

3시간 정도 걸린 것 같다.

 

 - HTML + CSS

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>Background Changer</title>
    <style>
      .wrap {
        height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }

      p {
        font-size: xx-large;
      }

      button {
        font-size: xx-large;
        padding: 20px;
        border-radius: 5px;
        background-color: gray;
        color: white;
        border: black;
      }
    </style>
    <script defer src="js_vanilla_BackgroundChanger.js"></script>
  </head>
  <body>
    <div class="wrap">
      <p>
        HEX COLOR :
        <span>#0021FQ</span>
      </p>
      <button>CLICK ME</button>
    </div>
  </body>
</html>

 display: flex과 flex-direction: Column을 통해 HEX COLOR 문단과 CLICK ME 버튼을 열로 나열했다.

 align-items: center와 justify-content: center를 통해 HEX COLOR 문단과 CLICK ME 버튼을 정중앙에 배치시켰다.

 defer src를 통해 JavaScript 파일을 불러왔다.

 

 - JavaScript

 

var arr = [
  "0",
  "1",
  "2",
  "3",
  "4",
  "5",
  "6",
  "7",
  "8",
  "9",
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
];

var button = document.querySelector("button");
var body = document.querySelector("body");
var span = document.querySelector("span");

button.addEventListener("click", function hexCode() {
  let result = "#";

  for (var i = 0; i < 6; i++) {
    var randomNumber = Math.floor(Math.random() * arr.length);
    var randomIndex = arr[randomNumber];
    result += randomIndex;
  }

  body.setAttribute("style", "background-color: " + result);
  span.textContent = result;
});

 일단 헥스 코드를 구성하는 16가지의 글자로 이루어진 배열부터 만들었다. 이부분은 힌트를 참조했다...

 

 CLICK ME라는 버튼을 "click"하면 function hexCode()가 실행되도록 이벤트를 추가했다.

 

 - function hexCode() 

1. 일단 헥스 코드가 #부터 시작할 수 있게, 또한 계속해서 변수가 재할당 될 수 있도록 let result = "#"을 선언했다.

2. 헥스 코드는 #을 제외한 6개의 글자로 이루어지므로 6번 반복되는 for문을 만들었다.

3. 0부터 1미만의 난수를 추출하는 Math.random과 뒤의 소수를 없애는, 내림시키는 Math.floor를 사용하면 무작위의 정수를 출력시킬 수 있다.

 

 Math.random() 실행 시 0.336288..., 0.749572..., 0.182934과 같은 0과 1사이의 난수가 추출된다. 여기에 10을 곱하면, 즉 Math.random() * 10을 실행하면 3.36288..., 7.49572..., 1.82934...와 같은 숫자가 출력된다. 여기에 Math.floor까지 실행하면, 즉 Math.floor(Math.random() * 10) 실행 시 숫자가 내림되므로 3, 7, 1과 같은 0부터 10미만의 정수가 랜덤하게 출력되는 것이다.

 

 중간에 10이 아니라 16을 곱했다면 0부터 16미만의 정수가 랜덤하게 출력된다. 이를 통해서 배열의 Index가 랜덤하게 추출되는 코드를 짤 수 있는데, 그대로 짠 것이 var randomNumber이다. 이러한 0부터 16미만의 랜덤한 정수를 arr 배열의 Index로 넣으면, arr 배열의 value들을 랜덤하게 추출할 수 있다.

 

 그리고 result += randomIndex를 통해, for문 안에서 6번 실행될 때마다 문자열이 계속해서 더해질 수 있도록 했다.

ex)

i = 0, result = "#" + "A" = "#A"

i = 1, result = "#A" + "6" = "#A6"

i = 2, result = "#A6" + "B" = "#A6B"

...

 

4. 마지막으로 setAttribute를 통하여 body에 style 속성을 추가하고 background-color가 result 값(for문을 마치면 최종적으로는 헥스 코드가 되어있다)에 맞게 설정되도록 했다. 또한 textContent를 통해 UI에 나타나는 헥스 코드 또한 result 값이 나타나도록 했다. 

  • Event

 자바스크립트에서 가장 동적인 움직임을 줄 수 있는 부분이지 않나 싶다. 웹 사이트에서 우리가 화면의 일부를 클릭하거나 마우스를 갖다대면 여러가지 동작이 일어난다. 이러한 대부분의 동작(이벤트)들을 자바스크립트로 구현할 수 있다.

 

- addEventListener

 addEventListener를 통해 다양한 동작을 구현할 수 있다.

 위 사진과 같은 경우, link라는 변수에 class가 titlelink인 요소 중 가장 처음 것('Don't start with ~~~')을 넣었다. 그리고 이 link에 addEventListener를 통해 mouseover, 즉 마우스를 오버(갖다댔을 때)했을 때 우리가 원하는 function()이 실행된다. 여기서는 123을 출력하는 것이다.

 

 또 가장 쉬운 경우는 click이다. rank라는 변수에 class가 rank인 요소의 가장 첫 요소를 넣었다. 그리고 이 rank를 click했을 때 alert를 띄우는 function이 실행되도록 addEventListener를 사용했다.

 

 즉 addEventListener('a', b)로 어느 요소에 Event를 추가할 수 있는데, a는 어떤 동작이 취해지면 되는지, 즉 트리거가 오면 되고 b에는 그 트리거가 만족되었을 때 실행되었으면 하는 function이 오면 된다. 여기서 a 인자는 event type, b 인자는 event handler 혹은 event listener라고 칭한다.

 

  • Event 객체

 function(), 이 괄호 사이에 event라는 매개 변수를 넣어보자.

 위 코드는 tbody를 클릭했을 때 event가 출력되도록 짠 코드이다. tbody는 news.ycombinator.com의 대부분을 차지하는데 이 공간의 어느 곳을 클릭하든 event라는 매개변수가 출력되는 것이다. 위와 같은 경우 event라는 매개 변수에 내가 클릭한 곳, 동작에 대한 정보가 담기는 것이다.

 

 x 좌표, y 좌표 등등 여러가지 정보가 담겨 있다. 그 중에서 주로 사용하는 것이 target과 currentTarget이다.

target

 쉽게 말해서 내가 클릭한 곳이 HTML 파일로 어디에 속하는지를 보여줄 수 있는 정보가 target이다.

 

currentTarget

 currentTarget은 내가 addEventListener한, 즉 Event를 부여한 곳에 대한 정보가 담겨 있는 것이다. 여기서 우리는 tbody에 대해 function(event)가 일어나도록 했으므로 currentTarget은 tbody태그라고 보면 된다. ycombinator 사이트의 거의 대부분이라고 봐도 된다. event가 일어나게 되는 범위라고 생각하면 이해하기 쉬울 듯 하다.

 

 위의 코드는 tbody 아무데나 클릭했을 때 currentTarget(여기선 tbody)의 HTML 코드를 <div>123</div>로 바꾸도록 동작하게 하는 코드이다.

 

 event라고 지어 놓은 매개 변수는 보통 이벤트 객체라고 부른다.

 

 이벤트 관련 참고 자료 : https://developer.mozilla.org/ko/docs/Web/Events

 

이벤트 참조 | MDN

DOM 이벤트는 발생한 흥미로운 것을 코드에 알리기 위해 전달됩니다. 각 이벤트는 Event 인터페이스를 기반으로한 객체에 의해 표현되며 발생한 것에 대한 부가적인 정보를 얻는데 사용되는 추가

developer.mozilla.org

 MDN에 어떤 이벤트가 가능한지 잘 정리되어 있다. 굳이 외울 필요가 없고 필요할 때 해당 자료를 찾아보면 된다. 엄청 많기 때문에 외우기 어렵다.

  • Manipulating Elements, 요소 조종하기

 자바스크립트의 기본적인 목적은 웹사이트에 동적인 움직임을 주기 위함이다. 그러므로 요소를 선택해서 변화시킬 수 있어야 한다. 앞에서 요소를 선택하기 위한 방법으로 querySelector, querySelectorAll, getElementById, get ElementsByClassName, getElementsByTagName을 썼었다.(get을 쓸 때 id를 제외하곤 Element에 s가 붙는다)

 

 이번에는 선택된 요소에 class를 추가하거나 제거하고, text는 어떻게 추가하는지 등등, 요소를 조종하는 방법을 알아보겠다.

 class를 조종하는 방법에는 기본적으로 add, remove, toggle가 있다.

 

- add : class에 원하는 class name을 추가한다.

class에서 athing 다음에 world가 추가되었다.

- remove : class에 원하는 class name을 제거한다.

class에서 athing 다음에 world가 제거되었다.

- toggle : class에 원하는 class name이 없다면 추가하고, 원하는 class name이 이미 존재한다면 제거한다. 그리고 전자의 경우에는 true를 출력하고, 후자의 경우에는 false를 출력한다.

전자의 경우, class name에 world가 없었기 때문에 world라는 name이 class에 추가되고, true가 출력된다. 곧바로 다시 toggle을 실행할 경우, 이미 class name에 world가 존재하기 때문에 world라는 name이 class에서 제거되고 false가 출력된다.

 

 요소 자체를 추가하고 제거하는 방법은 다음과 같다.

 

- createElement : 요소를 생성할 수 있다.

menu라는 변수에 a 태그 요소를 담았다.

- setAttribute : 요소에 속성과 그 속성의 값을 부여할 수 있다.

하이퍼링크 속성을 추가했다.

- appendChild : 해당 태그의 맨 끝에 요소를 추가한다.

span이라는 부모 요소 안의 마지막에, menu라는 자식 요소를 추가했다.
menu 요소가 추가되었다.

- textContent : 요소의 text를 제어할 수 있다.

- style : CSS 요소를 제어할 수 있다.

CSS 속성이 추가되었다.

 

 Quiz

아래 두가지 예제 코드의 차이점을 분별하시오.

 

1.

const something = document.createElement("p");

for (let i = 0; i < 5; i++) {
  something.textContent = i;
  document.body.appendChild(something);
}

 

2.

for (let i = 0; i < 5; i++) {
  const something = document.createElement("p");
  something.textContent = i;
  document.body.appendChild(something);
}

 

 전자의 경우, something이 1번 선언된다. i가 0에서 4까지 5번 반복할 때마다 append는 되지만 반복될 때마다 추가되는 것이 아니라 text가 바뀔 뿐이다. 풀어 쓰면 다음과 같다.

const something = document.createElement('p');

something.textContent = 0;
document.body.appendChild(something);

something.textContent = 1;
document.body.appendChild(something);

something.textContent = 2;
document.body.appendChild(something);

something.textContent = 3;
document.body.appendChild(something);

something.textContent = 4;
document.body.appendChild(something);

 something은 1번 선언되었기 때문에 하나의 something만 추가된다. 처음에는 0이 추가되었겠지만, 0이 1로 바뀌고 2로 바뀌고 3으로 바뀌고 4로 바뀌는 것이다. 웹에는 4만 출력된다.

 

 이와 다르게 후자의 경우는 something이 5번 선언된다. 그리고 중요한 것은, for문 안에서 선언된 변수는 1번 끝날 때마다 사라지고 다시 새로운 메모리를 할당 받는다. 따라서 i가 0에서 4까지 5번 반복할 동안 새로운 something이 선언된다. 풀어 쓰면 다음과 같다.

const something = document.createElement('p');
something.textContent = '0';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '1';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '2';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '3';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '4';
document.body.appendChild(something);

 something이 선언될 때마다 text가 바뀌고 body에 추가된다. 웹에는 0부터 4까지의 숫자가 출력된다.

+ Recent posts