๐๐ผ Daily Mission โ
HTML/CSS โ
Day 3
์ค๋ฌธ์กฐ์ฌ ์์ ๋ฐ ํ์๊ฐ์
ํผ
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
Day 4
ํ๋กํ ํ์ด์ง, ์ฑํ
๋ฐฉ, ๋์ฌ๋
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
Day 5
์ฑํ
๋ฐฉ ๋๋ฒจ๋กญ, ๋ฐ์ํ ์น, ๋ฐ์ํ ์น ๋๋ฒจ๋กญ, ํด๋ก
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
๐ฉ๐ปโ๐ป ์ ์ถํ ์ฝ๋๋ณด๊ธฐ
JavaScript โ
๐ฉ๐ปโ๐ป StackBlitz Collections
day 6
๋ณ์์ ํ์
๊ฐ๋
๐ฉ๐ปโ๐ป JavaScript 1์ผ์ฐจ ๋ณด๋ฌผ ์์์ด๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 1์ผ์ฐจ ๋๋ฌผ ์ถ๋ ฅํ๊ธฐ
๐ก Node.js ํ๊ฒฝ์์๋ .js ํ์ผ์ ์คํํ ๋ ํฐ๋ฏธ๋์์ node main.js์ฒ๋ผ ๋ช ๋ น์ด๋ก ์ง์ ํธ์ถํด์ผ ํ๋ค๋ ๊ฒ์ ์ด๋ฒ์ ์๋กญ๊ฒ ์๊ฒ ๋์๋ค.
day 7
ํ์
๊ฐ๋
๋ฐ ๋ฉ์๋ ํ์ฉ
๐ฉ๐ปโ๐ป JavaScript 2์ผ์ฐจ ์ค๋ฅ ์์ ํ๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 2์ผ์ฐจ ์ฃผ์ฌ์ ๋ง๋ค๊ธฐ
// min ์ด์ max ์ดํ์ ์ ์๋ฅผ ๋ง๋ค๊ธฐ ์ํ ๊ณต์
Math.floor(Math.random() * (max - min + 1)) + min;
day 8
์กฐ๊ฑด๋ฌธ๊ณผ ๋ฐ๋ณต๋ฌธ
๐ฉ๐ปโ๐ป JavaScript 3์ผ์ฐจ ์์ด ๊ณ์ฐํ๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 3์ผ์ฐจ ๋ฐฐ๋ฌ ์ฃผ๋ฌธํ๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 3์ผ์ฐจ ์ค๋
๊ตฌํ๊ธฐ
day 9
๋ฐฐ์ด ๊ธฐ์ด ๋ฐ ๋ฐฐ์ด ๋ฐ๋ณต๋ฌธ
๐ฉ๐ปโ๐ป JavaScript 4์ผ์ฐจ ์ฃผ๊ฐ ๋
์ ์ด๋ฒคํธ
๐ฉ๐ปโ๐ป JavaScript 4์ผ์ฐจ ์ ๊ท ๊ณ ๊ฐ ์ ๋ณํ๊ธฐ
day 10
ํจ์ ๊ธฐ์ด
๐ฉ๐ปโ๐ป JavaScript 5์ผ์ฐจ ์ฃผ์ฌ์ ๋ง๋ค๊ธฐ 2
day 11
๊ฐ์ฒด ๊ธฐ์ด
๐ฉ๐ปโ๐ป JavaScript 6์ผ์ฐจ ๊ณ์ฐ๊ธฐ ๋ง๋ค๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 6์ผ์ฐจ ํ ์ผ ๋ชฉ๋ก ๊ด๋ฆฌํ๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 6์ผ์ฐจ ํ ์๋ฃ๊ตฌ์กฐ ๋ง๋ค๊ธฐ
day 12
๋ฐฐ์ด, ๊ฐ์ฒด ์์ฉ
๐ฉ๐ปโ๐ป JavaScript 7์ผ์ฐจ ์ง์ ๊ด๋ฆฌํ๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 7์ผ์ฐจ ๋ง์ ๋ฌผ๋ฆฌ์น๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 7์ผ์ฐจ ์คํ ์๋ฃ๊ตฌ์กฐ ๋ง๋ค๊ธฐ
day 13
ํจ์ ์์ฉ, ๊ตฌ์กฐ๋ถํดํ ๋น
day 14
DOM ๊ธฐ์ด, ์ด๋ฒคํธ ๊ฐ์ฒด
๐ฉ๐ปโ๐ป JavaScript 9์ผ์ฐจ ํ๋ฒ๊ฑฐ ์ฃผ๋ฌธ์
๐ฉ๐ปโ๐ป JavaScript 9์ผ์ฐจ ๋ก๋ ๋ฒํธ ์์ฑ๊ธฐ ๊ธฐ๋ฅ ์ถ๊ฐ ๊ตฌํ
๐ฉ๐ปโ๐ป JavaScript 9์ผ์ฐจ ๋ก๋ ๋น์ฒจ ๋ฒํธ ๋ฐ ๋ก๋ ๋ฒํธ ์๋ ์์ฑ
day 15
๋น๋๊ธฐ
๐ฉ๐ปโ๐ป JavaScript 10์ผ์ฐจ ์๊ฐ ํฌ์ฐฉ
day 16
๋ฐ์ดํฐ fetch
๐ฉ๐ปโ๐ป JavaScript 11์ผ์ฐจ ๊ฐ์์ง ํ์ด์ง ๋ง๋ค๊ธฐ
day 17
๊ณ์ฐ๊ธฐ | DAY 1_HTML๋ก ๋ชฉ์
๋ง๋ค๊ธฐ
๐ฉ๐ปโ๐ป ๊ณ์ฐ๊ธฐ GitHub
๐ ์งํ ๋ด์ฉ ์์ฝ โ
- ์ด๊ธฐ ํ๋ก์ ํธ ์
์
๋ฐ ํ๊ฒฝ ๊ตฌ์ฑ
โ npm init์ผ๋ก ํ๋ก์ ํธ ์ด๊ธฐํ, package.json ๋ฐ .gitignore ์์ฑ - ๊ณ์ฐ๊ธฐ UI ๋ชฉ์ ๋ฐ ๋ ์ด์์ ์์ฑ
- ๊ธฐ๋ณธ ์คํ์ผ๋ง ๋ฐ ๋ฒํผ ๊ทธ๋ฃน ๊ตฌ์ฑ
- README ์์ฑ: ํ๋ก์ ํธ ๊ฐ์ด๋ & ๋ค์ด๋ฐ ๊ท์น ์ ๋ฆฌ
๐จ ๊ฐ์ ํ ์ โ
๋ฏธ์
๊ฐ์ด๋์ ๋ช
ํํ ํด๋์ค๋ช
๊ท์น์ด ์์ด, ๊ฐ์ธ์ ์ผ๋ก BEM ๋ฐฉ์์ ๋ฐ๋ผ ๋ค์ด๋ฐ ๊ท์น์ ๋จผ์ ์ธ์ ์์
์ ์งํํ๋ค.
ํ์ง๋ง ์ดํ DAY 2 ๋ฏธ์
์ง๋ฅผ ํ์ธํด๋ณด๋ ํ์ ํด๋์ค๋ช
์ด ์ถ๊ฐ๋ก ์ง์ ๋์ด ์์ด, ์ผ๋ถ ํด๋์ค๋ช
์ ์์ ํด์ผ ํ ํ์๊ฐ ์๊ฒผ๋ค.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Calculator</title>
<link rel="stylesheet" href="./src/style.css" />
</head>
<body>
<main class="calculator">
<h1 class="a11y-hidden">Calculator</h1>
<div class="calc-container p-40">
<!-- calculator window buttons -->
<div class="calc__window-btns">
<button
class="calc__window-btn--close btn-xs"
aria-label="ํ๋ฉด ๋ซ๊ธฐ"
title="๋ซ๊ธฐ"
></button>
<button
class="calc__window-btn--min btn-xs"
aria-label="ํ๋ฉด ์ต์ํ"
title="์ต์ํ"
></button>
<button
class="calc__window-btn--max btn-xs"
aria-label="ํ๋ฉด ์ต๋ํ"
title="์ต๋ํ"
></button>
</div>
<!-- calculator display -->
<div class="calc__display p-40"></div>
<!-- calculator keypad -->
<div class="calc__keypad p-40"></div>
</div>
</main>
</body>
</html>
/* reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
}
button {
border: none;
background: none;
padding: 0;
cursor: pointer;
}
/* color variables */
:root {
--white: #ffffff;
--black: #212121;
--red: #ff5f57;
--yellow: #ffbd2e;
--green: #28c840;
}
/* calculator-layout */
.calculator {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.calc-container {
width: 600px;
height: 800px;
display: flex;
flex-direction: column;
gap: 20px;
border: 4px solid #2d2f36;
}
/* calculator-inner */
.calc__window-btns {
display: flex;
gap: 8px;
}
.calc__window-btn--close {
background-color: var(--red);
}
.calc__window-btn--min {
background-color: var(--yellow);
}
.calc__window-btn--max {
background-color: var(--green);
}
.calc__display {
height: 120px;
text-align: right;
border: 4px solid #9000ff;
}
.calc__keypad {
flex: 1;
border: 4px solid #0085f9;
}
/* utils */
.a11y-hidden {
position: absolute;
overflow: hidden;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
clip: rect(0, 0, 0, 0);
clip-path: inset(50%);
white-space: nowrap;
}
.btn-xs {
width: 32px;
height: 32px;
border-radius: 50%;
}
.p-40 {
padding: 40px;
}
day 18
๊ณ์ฐ๊ธฐ | DAY 2_HTML๋ก ๋ชฉ์
๋ง๋ค๊ธฐ, Flexbox๋ก ์ ๋ ฌ ๋ฐ ๋ฐฐ์นํ๊ธฐ
๐ฉ๐ปโ๐ป ๊ณ์ฐ๊ธฐ GitHub
๐ ์งํ ๋ด์ฉ ์์ฝ โ
- ๊ณ์ฐ๊ธฐ ๋ ์ด์์์ Flexbox ์ ์ฉํ์ฌ ์ ๋ ฌ ๋ฐ ๋ฐฐ์น ๊ตฌํ
- ๋ฒํผ ์ข ๋ฅ๋ณ ํด๋์ค ์ธ๋ถํ
- Pretendard ์นํฐํธ ์ ์ฉ ๋ฐ UI ์คํ์ผ๋ง ๋ฐ์
- README ์์ฑ: ๋ฐ๋ชจ url ๋ฐ ๋์์ธ ์์ ๋ฐ์
๐จ ๊ฐ์ ํ ์ โ
- display์ ์ถ๋ ฅ๋๋ ๊ธ์๊ฐ ๋ง์์ก์ ๋์ ํฐํธ ์ฌ์ด์ฆ ๋์์ ์์ง ๋ฏธ๊ตฌํ
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Calculator</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/pretendard@1.3.8/dist/web/static/pretendard.css"
/>
<link rel="stylesheet" href="./src/style.css" />
</head>
<body>
<main class="calculator">
<h1 class="a11y-hidden">๊ณ์ฐ๊ธฐ</h1>
<div class="calc-container">
<!-- calculator window buttons -->
<div class="calc__window-btns">
<button
type="button"
class="calc__window-btn close"
aria-label="ํ๋ฉด ๋ซ๊ธฐ"
title="๋ซ๊ธฐ"
></button>
<button
type="button"
class="calc__window-btn min"
aria-label="ํ๋ฉด ์ต์ํ"
title="์ต์ํ"
></button>
<button
type="button"
class="calc__window-btn max"
aria-label="ํ๋ฉด ์ต๋ํ"
title="์ต๋ํ"
></button>
</div>
<!-- calculator display -->
<!--
- ์คํฌ๋ฆฐ๋ฆฌ๋ ์๋ ์ฝ๊ธฐ: role="status" + aria-live="polite"
- ํค๋ณด๋ ํฌ์ปค์ค ๊ฐ๋ฅ: tabindex="0"
- input ๋์ div ์ฌ์ฉ (์ง์ ์
๋ ฅ ์์ด ๋ฒํผ ํด๋ฆญ์ผ๋ก๋ง ๋์)
-->
<div
class="calc__display"
role="status"
aria-live="polite"
aria-label="๊ณ์ฐ ๊ฒฐ๊ณผ"
tabindex="0"
>
0
</div>
<!-- calculator buttons -->
<div class="calc__buttons">
<button type="button" class="button function clear" aria-label="์ด๊ธฐํ" title="์ด๊ธฐํ">
<span class="button__inner">C</span>
</button>
<button type="button" class="button function" aria-label="๋ถํธ ์ ํ" title="๋ถํธ ์ ํ">
<span class="button__inner">ยฑ</span>
</button>
<button type="button" class="button function" aria-label="ํผ์ผํธ" title="ํผ์ผํธ">
<span class="button__inner">%</span>
</button>
<button type="button" class="button operator" aria-label="๋๋๊ธฐ" title="๋๋๊ธฐ">
<span class="button__inner">/</span>
</button>
<button type="button" class="button number">
<span class="button__inner">7</span>
</button>
<button type="button" class="button number">
<span class="button__inner">8</span>
</button>
<button type="button" class="button number">
<span class="button__inner">9</span>
</button>
<button type="button" class="button operator" aria-label="๊ณฑํ๊ธฐ" title="๊ณฑํ๊ธฐ">
<span class="button__inner">*</span>
</button>
<button type="button" class="button number">
<span class="button__inner">4</span>
</button>
<button type="button" class="button number">
<span class="button__inner">5</span>
</button>
<button type="button" class="button number">
<span class="button__inner">6</span>
</button>
<button type="button" class="button operator" aria-label="๋นผ๊ธฐ" title="๋นผ๊ธฐ">
<span class="button__inner">-</span>
</button>
<button type="button" class="button number">
<span class="button__inner">1</span>
</button>
<button type="button" class="button number">
<span class="button__inner">2</span>
</button>
<button type="button" class="button number">
<span class="button__inner">3</span>
</button>
<button type="button" class="button operator" aria-label="๋ํ๊ธฐ" title="๋ํ๊ธฐ">
<span class="button__inner">+</span>
</button>
<button type="button" class="button number zero">
<span class="button__inner">0</span>
</button>
<button type="button" class="button decimal" aria-label="์์์ " title="์์์ ">
<span class="button__inner">.</span>
</button>
<button type="button" class="button equal" aria-label="๊ณ์ฐํ๊ธฐ" title="๊ณ์ฐํ๊ธฐ">
<span class="button__inner">=</span>
</button>
</div>
</div>
<div class="calc-shadow" aria-hidden="true"></div>
</main>
<script src="./src/script.js"></script>
</body>
</html>
/* reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
font-family: "Pretendard", sans-serif;
background-color: var(--black);
}
button {
border: none;
background: none;
padding: 0;
cursor: pointer;
}
/* color variables */
:root {
--white: #ffffff;
--gray-100: #eeeeee;
--gray-200: #dadada;
--gray-300: #b8b8b8;
--gray-400: #444444;
--gray-600: #666666;
--gray-700: #777777;
--gray-800: #8c8c8c;
--black: #222222;
/* status color */
--red: #ff5f57;
--yellow: #ffbd2e;
--green: #28c840;
}
/* calculator-layout */
.calculator {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.calc-container {
position: relative;
display: flex;
flex-direction: column;
gap: 20px;
padding: 20px;
border-radius: 8px;
border: 2px solid var(--white);
background-color: var(--gray-100);
z-index: 100;
}
.calc-shadow {
position: absolute;
bottom: 136px;
width: 384px;
height: 30px;
background: var(--gray-300);
border-radius: 0 0 12px 12px;
background: linear-gradient(180deg, var(--gray-400) -20%, var(--gray-700) 90%);
}
/* calculator inner */
/* window buttons */
.calc__window-btns {
display: flex;
gap: 8px;
}
.calc__window-btn {
width: 20px;
height: 20px;
border-radius: 50%;
background-position: center;
background-repeat: no-repeat;
background-size: 16px;
background-color: var(--gray-600);
transition: all 0.2s ease;
}
.calc__window-btn.close:hover {
background-color: var(--red);
background-image: url(./images/ico_close.svg);
}
.calc__window-btn.min:hover {
background-color: var(--yellow);
background-image: url(./images/ico_min.svg);
}
.calc__window-btn.max:hover {
background-color: var(--green);
background-image: url(./images/ico_max.svg);
}
/* display */
.calc__display {
width: 340px;
height: 88px;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 20px;
font-size: 32px;
border-radius: 8px;
color: var(--gray-100);
background-color: var(--black);
}
/* buttons */
.calc__buttons {
width: 100%;
max-width: 340px;
display: flex;
flex-wrap: wrap;
gap: 4px;
border-radius: 8px;
padding: 4px;
background-color: var(--black);
}
.button {
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
color: var(--gray-600);
padding: 20px;
border-radius: 4px;
background-color: var(--gray-200);
transition: all 0.2s ease;
}
.button__inner {
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
font-size: 18px;
border-radius: 50%;
background: linear-gradient(150deg, var(--gray-300) 20%, var(--gray-100) 60%);
}
.button.zero {
flex-grow: 1;
}
.button:hover {
background-color: var(--gray-300);
}
.button:active {
transform: scale(0.9);
background-color: var(--gray-800);
box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.4);
}
/* utils */
.a11y-hidden {
position: absolute;
overflow: hidden;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
clip: rect(0, 0, 0, 0);
clip-path: inset(50%);
white-space: nowrap;
}
day 19
๊ณ์ฐ๊ธฐ | DAY 3_๋ฒํผ ํด๋ฆญ ์ ๋์คํ๋ ์ด์ ํ์๋๋๋ก ๋ง๋ค๊ธฐ
๐ฉ๐ปโ๐ป ๊ณ์ฐ๊ธฐ GitHub
๐ ์งํ ๋ด์ฉ ์์ฝ โ
- ๊ฐ ๋ฒํผ์ ํด๋ฆญํ์ ๋ console์ ๊ฐ ๋ฒํผ์ value ์ถ๋ ฅ
- ์ซ์ ๋์คํ๋ ์ด์ ํ์
- ์์์ ์ค๋ณต ์ ๋ ฅ ๋ฐฉ์ง ๋ก์ง ๊ตฌํ
- Clear ๊ธฐ๋ฅ ์ถ๊ฐ
- ์ฝ์์ ์ ๋ ฅ ํ๋ฆ ์๊ฐ์ ์ผ๋ก ๋๋ฒ๊น
๐จ ๊ฐ์ ํ ์ โ
btnClick
ํจ์ ๋ด๋ถ์์ ์กฐ๊ฑด๋ฌธ์ด ๋ง์ ๋ณต์กํ๊ณ ,console.log(clickedBtnText)
๊ฐ ์ค๋ณต๋์ด ์์ด์ ๋ฒํผ ํ์ ๋ณ ๋์์ ํจ์๋ก ๋ถ๋ฆฌํ๊ฑฐ๋, switch๋ฌธ ๋ฑ์ผ๋ก ๋ฆฌํฉํ ๋ง ์งํ ์์ - ์ฝ์์ ๋ชจ๋
clickedBtnText
๋ฅผ ์ถ๋ ฅํ์ง๋ง, ์ค์ ๋์์ ํ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์์ด ๋ฏธ์ ์๋ฃ ํ ๊ฐ์ ์์ - ๋์คํ๋ ์ด ๊ธ์ ์์ ๋ฐ๋ฅธ ๊ธ์ ํฌ๊ธฐ ์กฐ์ ์ ์์ง ๊ตฌํ ์
- ์ฐ์ฐ์, ๊ธฐ๋ฅ, ๊ฒฐ๊ณผ ๋ฒํผ์ ๋ํ ๋์ ๊ตฌํ์ ๋ฏธ๊ตฌํ ์ํ (day 4)
๐งฉ forEach()๋ฅผ ์ฌ์ฉํ ์ด์ (feat.map() ๋ฉ์๋) โ
// ์ ์ถ ์ฝ๋
// ๊ณ์ฐ๊ธฐ ๋ฒํผ์ ํด๋ฆญ ์ด๋ฒคํธ ๋ฑ๋ก
calcButtons.forEach((button) => {
button.addEventListener("click", btnClick);
});
// ๐ ๋๋ฒ๊น
์ฉ ์ถ๋ ฅ
console.log(calcButtons);
// ๊ณ์ฐ๊ธฐ ๋ฒํผ(.button)์ ๋ชจ๋ ์ ํํ๋ฉด NodeList๊ฐ ๋ฐํ๋จ
// NodeList๋ ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ง๋ง, forEach() ๋ฉ์๋๋ก ์ํ ๊ฐ๋ฅ
- ๋ชจ๋ ๋ฒํผ์ ํด๋ฆญ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํด
forEach()
๋ฅผ ์ฌ์ฉํ๋ค. - ์ ์ญ์์
const calcButtons = document.querySelectorAll(".button");
๋ฅผ ํตํด ๋ฒํผ๋ค์ ๊ฐ์ ธ์ค๊ณ , ์ฝ์์ ์ถ๋ ฅํด๋ณด๋ฉดNodeList
๊ฐ ๋ฐํ๋๋ค.NodeList
๋ ๋ฐฐ์ด๊ณผ ๋น์ทํ ๊ตฌ์กฐ์ ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ด๋ฉฐ,forEach()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
๐งฉ map()
map()
์ ์๋ณธ ๋ฐฐ์ด์ ๊ธฐ๋ฐ์ผ๋ก์๋ก์ด ๋ฐฐ์ด ์์ฑํ๊ณ ๋ฐํ
ํ๋ ๊ฒฝ์ฐ์ ๋ง์ด ์ฌ์ฉ๋๋ ๋ฉ์๋์ด๊ธฐ ๋๋ฌธ์ ๋ฆฌํด๊ฐ์ด ํ์์๋ ๊ฒฝ์ฐ์๋map()
๋ณด๋ค๋forEach()
๊ฐ ์ ํฉํ๋ค.- ํ ๊ณ์ฐ๊ธฐ์์๋ ๊ฐ ๋ฒํผ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ถ์ฌํ๋ ์์
์ด๋ฏ๋ก
forEach()
๋ก ๊ตฌํํ๋ค.
๐งฉ NodeList?
NodeList
๋ ๋ฐฐ์ด๊ณผ ๋น์ทํ ๊ตฌ์กฐ์ ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ด๋ฉฐ, ์ธ๋ฑ์ค๋ก ์ ๊ทผํ ์ ์๊ณ , length ์์ฑ๋ ์กด์ฌํ์ง๋ง, ์ง์ง ์๋ฐ์คํฌ๋ฆฝํธ ๋ฐฐ์ด์ด ์๋๊ธฐ ๋๋ฌธ์ push(), pop() ๋ฑ์ ๋ฐฐ์ด ๋ฉ์๋๋ ์ฌ์ฉํ ์ ์๋ค.- ํ์ง๋ง, NodeList๋ forEach() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋
iterable ๊ฐ์ฒด
์ด๋ค. ๋ฐฐ์ด์ฒ๋ผ ์์๋ฅผ ์ํํ๋ฉฐ ๊ฐ ๋ฒํผ์ ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ ์ ์๋ค.
๐งฉ iterable ๊ฐ์ฒด?
- ๐ iterable object
- ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋?
for...of
,spread
,Array.from()
๋ฑ์ ์ฌ์ฉํ ์ ์๋ ๊ฐ์ฒด๋ก์, ๋ด๋ถ์Symbol.iterator()
๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด์ด๋ค. - ๋ฐฐ์ด, ๋ฌธ์์ด, NodeList, Set, Map ๋ฑ์ ๋ชจ๋ iterable์ด๊ณ
์ผ๋ฐ ๊ฐ์ฒด
๋ ๊ธฐ๋ณธ์ ์ผ๋ก iterable์ด ์๋๋ค. - ์ด๋ ์ฌ์ฉ๋๋
Symbol.iterator
๋์ฌ๋ณผ(Symbol)
ํ์ ์ ๊ฐ์ด๊ธฐ ๋๋ฌธ์, ๊ทธ๋์ ๋งค๋ฒ ์ง๋์ณค๋ ํ๋ฆฌ๋ฏธํฐ๋ธ ํ์ ์ค '์ฌ๋ณผ(Symbol)'์ ๋ํด ์ ๋๋ก ์ดํดํ ํ์์ฑ์ ๋๊ผ๋ค.. ๐ซ
reference โ
- [JavaScript ํ์ต์ฝํ ์ธ 7์ผ์ฐจ map]
- ๐ MDN forEach()
- ๐ MDN map()
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Calculator</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/pretendard@1.3.8/dist/web/static/pretendard.css"
/>
<link rel="stylesheet" href="./src/style.css" />
</head>
<body>
<main class="calculator">
<h1 class="a11y-hidden">๊ณ์ฐ๊ธฐ</h1>
<div class="calc-container">
<!-- calculator window buttons -->
<div class="calc__window-btns">
<button
type="button"
class="calc__window-btn close"
aria-label="ํ๋ฉด ๋ซ๊ธฐ"
title="๋ซ๊ธฐ"
></button>
<button
type="button"
class="calc__window-btn min"
aria-label="ํ๋ฉด ์ต์ํ"
title="์ต์ํ"
></button>
<button
type="button"
class="calc__window-btn max"
aria-label="ํ๋ฉด ์ต๋ํ"
title="์ต๋ํ"
></button>
</div>
<!-- calculator display -->
<!--
- ์คํฌ๋ฆฐ๋ฆฌ๋ ์๋ ์ฝ๊ธฐ: role="status" + aria-live="polite"
- ํค๋ณด๋ ํฌ์ปค์ค ๊ฐ๋ฅ: tabindex="0"
- input ๋์ div ์ฌ์ฉ (์ง์ ์
๋ ฅ ์์ด ๋ฒํผ ํด๋ฆญ์ผ๋ก๋ง ๋์)
-->
<div
class="calc__display"
role="status"
aria-live="polite"
aria-label="๊ณ์ฐ ๊ฒฐ๊ณผ"
tabindex="0"
>
0
</div>
<!-- calculator buttons -->
<div class="calc__buttons">
<button type="button" class="button function clear" aria-label="์ด๊ธฐํ" title="์ด๊ธฐํ">
<span class="button__inner">C</span>
</button>
<button type="button" class="button function" aria-label="๋ถํธ ์ ํ" title="๋ถํธ ์ ํ">
<span class="button__inner">ยฑ</span>
</button>
<button type="button" class="button function" aria-label="ํผ์ผํธ" title="ํผ์ผํธ">
<span class="button__inner">%</span>
</button>
<button type="button" class="button operator" aria-label="๋๋๊ธฐ" title="๋๋๊ธฐ">
<span class="button__inner">/</span>
</button>
<button type="button" class="button number">
<span class="button__inner">7</span>
</button>
<button type="button" class="button number">
<span class="button__inner">8</span>
</button>
<button type="button" class="button number">
<span class="button__inner">9</span>
</button>
<button type="button" class="button operator" aria-label="๊ณฑํ๊ธฐ" title="๊ณฑํ๊ธฐ">
<span class="button__inner">*</span>
</button>
<button type="button" class="button number">
<span class="button__inner">4</span>
</button>
<button type="button" class="button number">
<span class="button__inner">5</span>
</button>
<button type="button" class="button number">
<span class="button__inner">6</span>
</button>
<button type="button" class="button operator" aria-label="๋นผ๊ธฐ" title="๋นผ๊ธฐ">
<span class="button__inner">-</span>
</button>
<button type="button" class="button number">
<span class="button__inner">1</span>
</button>
<button type="button" class="button number">
<span class="button__inner">2</span>
</button>
<button type="button" class="button number">
<span class="button__inner">3</span>
</button>
<button type="button" class="button operator" aria-label="๋ํ๊ธฐ" title="๋ํ๊ธฐ">
<span class="button__inner">+</span>
</button>
<button type="button" class="button number zero">
<span class="button__inner">0</span>
</button>
<button type="button" class="button decimal" aria-label="์์์ " title="์์์ ">
<span class="button__inner">.</span>
</button>
<button type="button" class="button equal" aria-label="๊ณ์ฐํ๊ธฐ" title="๊ณ์ฐํ๊ธฐ">
<span class="button__inner">=</span>
</button>
</div>
</div>
<div class="calc-shadow" aria-hidden="true"></div>
</main>
<script src="./src/script.js"></script>
</body>
</html>
/* reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
font-family: "Pretendard", sans-serif;
background-color: var(--black);
}
button {
border: none;
background: none;
padding: 0;
cursor: pointer;
}
/* color variables */
:root {
--white: #ffffff;
--gray-100: #eeeeee;
--gray-200: #dadada;
--gray-300: #b8b8b8;
--gray-400: #444444;
--gray-600: #666666;
--gray-700: #777777;
--gray-800: #8c8c8c;
--black: #222222;
/* status color */
--red: #ff5f57;
--yellow: #ffbd2e;
--green: #28c840;
}
/* calculator-layout */
.calculator {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.calc-container {
position: relative;
display: flex;
flex-direction: column;
gap: 20px;
padding: 20px;
border-radius: 8px;
border: 2px solid var(--white);
background-color: var(--gray-100);
z-index: 100;
}
.calc-shadow {
position: absolute;
bottom: 136px;
width: 384px;
height: 30px;
background: var(--gray-300);
border-radius: 0 0 12px 12px;
background: linear-gradient(180deg, var(--gray-400) -20%, var(--gray-700) 90%);
}
/* calculator inner */
/* window buttons */
.calc__window-btns {
display: flex;
gap: 8px;
}
.calc__window-btn {
width: 20px;
height: 20px;
border-radius: 50%;
background-position: center;
background-repeat: no-repeat;
background-size: 16px;
background-color: var(--gray-600);
transition: all 0.2s ease;
}
.calc__window-btn.close:hover {
background-color: var(--red);
background-image: url(./images/ico_close.svg);
}
.calc__window-btn.min:hover {
background-color: var(--yellow);
background-image: url(./images/ico_min.svg);
}
.calc__window-btn.max:hover {
background-color: var(--green);
background-image: url(./images/ico_max.svg);
}
/* display */
.calc__display {
width: 340px;
height: 88px;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 20px;
font-size: 32px;
border-radius: 8px;
color: var(--gray-100);
background-color: var(--black);
}
/* buttons */
.calc__buttons {
width: 100%;
max-width: 340px;
display: flex;
flex-wrap: wrap;
gap: 4px;
border-radius: 8px;
padding: 4px;
background-color: var(--black);
}
.button {
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
color: var(--gray-600);
padding: 20px;
border-radius: 4px;
background-color: var(--gray-200);
transition: all 0.2s ease;
}
.button__inner {
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
font-size: 18px;
border-radius: 50%;
background: linear-gradient(150deg, var(--gray-300) 20%, var(--gray-100) 60%);
}
.button.zero {
flex-grow: 1;
}
.button:hover {
background-color: var(--gray-300);
}
.button:active {
transform: scale(0.9);
background-color: var(--gray-800);
box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.4);
}
/* utils */
.a11y-hidden {
position: absolute;
overflow: hidden;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
clip: rect(0, 0, 0, 0);
clip-path: inset(50%);
white-space: nowrap;
}
// ๊ณ์ฐ๊ธฐ DOM ์์ (์ ์ญ)
const calcButtons = document.querySelectorAll(".button"); // ๊ณ์ฐ๊ธฐ ๋ฒํผ๋ค
const calcDisplay = document.querySelector(".calc__display"); // ๊ณ์ฐ๊ธฐ ํ๋ฉด
// ๋ฒํผ ํด๋ฆญ ์ ์คํ
const btnClick = (event) => {
// ํด๋ฆญ๋ ๋ฒํผ ๊ด๋ จ ๋ณ์ (์ง์ญ)
const clickedBtn = event.currentTarget; // ํด๋ฆญ๋ ๋ฒํผ ์์
const clickedBtnText = clickedBtn.querySelector(".button__inner").textContent; // ๋ฒํผ ์์ ํ
์คํธ
// ๋ฒํผ ์ข
๋ฅ ํ์ธ
const isNumber = clickedBtn.classList.contains("number"); // ์ซ์ ๋ฒํผ ์ฌ๋ถ ํ์ธ
const isDecimal = clickedBtn.classList.contains("decimal"); // ์์์ ๋ฒํผ ์ฌ๋ถ ํ์ธ
const isClear = clickedBtn.classList.contains("clear"); // ์ด๊ธฐํ(C) ๋ฒํผ ์ฌ๋ถ ํ์ธ
const isFunction = clickedBtn.classList.contains("function"); // ๊ธฐ๋ฅ ๋ฒํผ ์ฌ๋ถ ํ์ธ
const isOperator = clickedBtn.classList.contains("operator"); // ์ฐ์ฐ์ ๋ฒํผ ์ฌ๋ถ ํ์ธ
const isEqual = clickedBtn.classList.contains("equal"); // ๊ฒฐ๊ณผ ๋ฒํผ ์ฌ๋ถ
// ํ์ฌ display ํ๋ฉด(๊ณต๋ฐฑ ์ ๊ฑฐ๋ ๋ฌธ์์ด)
const currentDisplay = calcDisplay.textContent.trim();
// ์ด๊ธฐํ(C) ๋ฒํผ ํด๋ฆญ ์: ๋์คํ๋ ์ด 0์ผ๋ก ์ด๊ธฐํ
if (isClear) {
console.log(clickedBtnText);
calcDisplay.textContent = 0;
return; // ์ข
๋ฃ
}
// ๊ฒฐ๊ณผ ๋ฒํผ
if (isEqual) {
console.log(clickedBtnText);
return;
}
// ์ฐ์ฐ์ ๋ฒํผ ํด๋ฆญ ์: ์ฝ์ ์ถ๋ ฅ
if (isOperator) {
console.log(clickedBtnText);
return;
}
// ๊ธฐ๋ฅ ๋ฒํผ ํด๋ฆญ ์: ์ฝ์ ์ถ๋ ฅ
if (isFunction) {
console.log(clickedBtnText);
return;
}
// ์์์ ์ค๋ณต ์
๋ ฅ ๋ฐฉ์ง: ๋์คํ๋ ์ด์ ์์์ ์ด ์๋ค๋ฉด ์ถ๊ฐ
if (isDecimal) {
console.log(clickedBtnText);
if (!currentDisplay.includes(".")) {
calcDisplay.textContent = currentDisplay + clickedBtnText;
}
return; // ์ด๋ฏธ ํฌํจ๋์ด ์๋ค๋ฉด ๋ฆฌํด(๋ฌด์)
}
// ์ซ์ ํด๋ฆญ ์: ํ์ฌ ํ๋ฉด์ด 0์ด๋ฉด ํด๋ฆญ๋ ๋ฒํผ์ ๊ฐ์ผ๋ก ๋์ฒด, ์๋๋ฉด ์ด์ด ๋ถ์ด๊ธฐ
if (isNumber) {
console.log(clickedBtnText);
if (currentDisplay === "0") {
calcDisplay.textContent = clickedBtnText;
} else {
calcDisplay.textContent += clickedBtnText;
}
}
};
// ๊ณ์ฐ๊ธฐ ๋ฒํผ์ ํด๋ฆญ ์ด๋ฒคํธ ๋ฑ๋ก
calcButtons.forEach((button) => {
button.addEventListener("click", btnClick);
});
// ๐ ๋๋ฒ๊น
์ฉ ์ถ๋ ฅ
// console.log(calcButtons);
// ๊ณ์ฐ๊ธฐ ๋ฒํผ(.button)์ ๋ชจ๋ ์ ํํ๋ฉด NodeList๊ฐ ๋ฐํ๋จ
// NodeList๋ ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ง๋ง, forEach() ๋ฉ์๋๊ฐ ์์ด์ ์ํ ๊ฐ๋ฅ
day 20
๊ณ์ฐ๊ธฐ | DAY 4_๊ณ์ฐ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ & DAY 5_๋ฐฐํฌ
๐ฉ๐ปโ๐ป ๊ณ์ฐ๊ธฐ GitHub
๐ ์งํ ๋ด์ฉ ์์ฝ โ
btnClick
ํจ์์ ๋ณต์กํ ์กฐ๊ฑด๋ฌธ์ ๊ฐ ๋ฒํผ๋ง๋ค ๊ธฐ๋ฅ๋ณ๋ก ํจ์ ๋ถ๋ฆฌ- ๊ฐ ๋ฒํผ์ data-set ์์ฑ์ ์ถ๊ฐํด ๋ฒํผ ์์ ํ ์คํธ๋ฅผ ์ง์ ์ฝ์ง ์๊ณ ๊ฐ์ ๊ฐ์ ธ์ค๋๋ก ๊ฐ์
- firstOperand, secondOperand, operator ์ ์ญ ๋ณ์ ์ถ๊ฐ ๋ฐ ์ํ ์ ์ฅ
=
๋ฒํผ ํด๋ฆญ ์ ์ฐ์ฐ ๊ฒฐ๊ณผ ์ถ๋ ฅ ๋ฐ ์ฐ์ ๊ณ์ฐ ๊ตฌํ%
,ยฑ
,C
๊ธฐ๋ฅ ๋ฒํผ ๊ตฌํ- 0์ผ๋ก ๋๋๋ ์ํฉ์์ "์ ์๋์ง ์์" ๋ฉ์์ง ์ถ๋ ฅ ๋ฐ ์ํ ์ด๊ธฐํ๋ฅผ ์ํด
checkNaN()
์ถ๊ฐ - ํ๋ฉด์ ์ซ์๊ฐ ๊ธธ์ด์ง๋ฉด ํฐํธ ํฌ๊ธฐ๊ฐ ์ค์ด๋ค๋๋ก
adjustDisplayFontSize()
ํจ์ ์ถ๊ฐ
๐ ๋ฐฐํฌ ๊ณผ์ โ
- Vercel์ ์ด์ฉํด ๊ณ์ฐ๊ธฐ ํ๋ก์ ํธ ๋ฐฐํฌ
- .dev ๋๋ฉ์ธ์ HTTPS๊ฐ ํ์๋ผ Cloudflare๋ฅผ ์ด์ฉํด ๋ณด์ ์ธ์ฆ ์ฒ๋ฆฌ
- ๊ฐ๋น์์์ ๋๋ฉ์ธ ๊ตฌ์ โ Cloudflare์ ๋ฑ๋ก ํ DNS ์ค์ (CNAME, A ๋ ์ฝ๋)
- Vercel ํ๋ก์ ํธ ์ค์ ์์ Custom Domain ์ฐ๊ฒฐ ์๋ฃ
- ํ๋ก์ ํธ ๊ตฌ์กฐ ์ ๋ฆฌ๋ฅผ ์ํด calculator ๋ ํฌ๋ฅผ hyebin-dev monorepo๋ก ๋ง์ด๊ทธ๋ ์ด์ (?)
๐จ ๊ฐ์ ํ ์ โ
์ ์ญ ๋ณ์
firstOperand
,operator
๊ฐ์ ์ํ๋ค์ ํ๋์state ๊ฐ์ฒด
๋ก ๋ฌถ์ด์ ๊ด๋ฆฌํ ์์ โ ์ค์๊ฐ ์ธ์ ์์ ์์ด๋์ด๋ฅผ ์ป์๊ณ , ๊ตฌ์กฐ๊ฐ ํจ์ฌ ๊น๋ํด์ง ๊ฒ ๊ฐ์์ ๊ผญ ์ ์ฉํด๋ณด๊ณ ์ถ๋ค.js// ์์ const defaultState = { firstOperand: null, secondOperand: null, operator: null, shouldResetDisplay: false, }; const state = { ...defaultState }; Object.assign(state, defaultState);
calcDisplay.textContent
๋ฅผ ์ง์ ์์ ํ๋ ์ฝ๋๊ฐ ๋ฐ๋ณต๋ผ์, getDisplay(), setDisplay() ๊ฐ์ ํจ์๋ก display ๊ด๋ จ ์ฝ๋๋ฅผ ๋ฐ๋ก ๋นผ์ ๊ด๋ฆฌํ๊ณ ์ค๋ณต์ ์ค์ด๋ ค ํ๋ค.์ง๊ธ์ ํ ํ์ผ ์์ ๋ชจ๋ ๊ธฐ๋ฅ์ด ์์ฌ ์์ด์, ๊ธฐ๋ฅ๋ณ๋ก JS ํ์ผ์ ๋๋ ๋ณด๋ ค ํ๋ค. (์ ํธ, ๊ธฐ๋ฅ, ๊ณ์ฐ, ์ด๋ฒคํธ ๋ฑ)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Calculator</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/pretendard@1.3.8/dist/web/static/pretendard.css"
/>
<link rel="stylesheet" href="./src/style.css" />
</head>
<body>
<main class="calculator">
<h1 class="a11y-hidden">๊ณ์ฐ๊ธฐ</h1>
<div class="calc-container">
<!-- calculator window buttons -->
<div class="calc__window-btns">
<button
type="button"
class="calc__window-btn close"
aria-label="ํ๋ฉด ๋ซ๊ธฐ"
title="๋ซ๊ธฐ"
></button>
<button
type="button"
class="calc__window-btn min"
aria-label="ํ๋ฉด ์ต์ํ"
title="์ต์ํ"
></button>
<button
type="button"
class="calc__window-btn max"
aria-label="ํ๋ฉด ์ต๋ํ"
title="์ต๋ํ"
></button>
</div>
<!-- calculator display -->
<!--
- ์คํฌ๋ฆฐ๋ฆฌ๋ ์๋ ์ฝ๊ธฐ: role="status" + aria-live="polite"
- ํค๋ณด๋ ํฌ์ปค์ค ๊ฐ๋ฅ: tabindex="0"
- input ๋์ div ์ฌ์ฉ (์ง์ ์
๋ ฅ ์์ด ๋ฒํผ ํด๋ฆญ์ผ๋ก๋ง ๋์)
-->
<div
class="calc__display"
role="status"
aria-live="polite"
aria-label="๊ณ์ฐ ๊ฒฐ๊ณผ"
tabindex="0"
>
0
</div>
<!-- calculator buttons -->
<div class="calc__buttons">
<button
type="button"
class="button function clear"
data-set="C"
aria-label="์ด๊ธฐํ"
title="์ด๊ธฐํ"
>
<span class="button__inner">C</span>
</button>
<button
type="button"
class="button function"
data-set="ยฑ"
aria-label="๋ถํธ ์ ํ"
title="๋ถํธ ์ ํ"
>
<span class="button__inner">ยฑ</span>
</button>
<button
type="button"
class="button function"
data-set="%"
aria-label="ํผ์ผํธ"
title="ํผ์ผํธ"
>
<span class="button__inner">%</span>
</button>
<button
type="button"
class="button operator"
data-set="/"
aria-label="๋๋๊ธฐ"
title="๋๋๊ธฐ"
>
<span class="button__inner">/</span>
</button>
<button type="button" class="button number" data-set="7">
<span class="button__inner">7</span>
</button>
<button type="button" class="button number" data-set="8">
<span class="button__inner">8</span>
</button>
<button type="button" class="button number" data-set="9">
<span class="button__inner">9</span>
</button>
<button
type="button"
class="button operator"
data-set="*"
aria-label="๊ณฑํ๊ธฐ"
title="๊ณฑํ๊ธฐ"
>
<span class="button__inner">*</span>
</button>
<button type="button" class="button number" data-set="4">
<span class="button__inner">4</span>
</button>
<button type="button" class="button number" data-set="5">
<span class="button__inner">5</span>
</button>
<button type="button" class="button number" data-set="6">
<span class="button__inner">6</span>
</button>
<button type="button" class="button operator" data-set="-" aria-label="๋นผ๊ธฐ" title="๋นผ๊ธฐ">
<span class="button__inner">-</span>
</button>
<button type="button" class="button number" data-set="1">
<span class="button__inner">1</span>
</button>
<button type="button" class="button number" data-set="2">
<span class="button__inner">2</span>
</button>
<button type="button" class="button number" data-set="3">
<span class="button__inner">3</span>
</button>
<button
type="button"
class="button operator"
data-set="+"
aria-label="๋ํ๊ธฐ"
title="๋ํ๊ธฐ"
>
<span class="button__inner">+</span>
</button>
<button type="button" class="button number zero" data-set="0">
<span class="button__inner">0</span>
</button>
<button
type="button"
class="button decimal"
data-set="."
aria-label="์์์ "
title="์์์ "
>
<span class="button__inner">.</span>
</button>
<button
type="button"
class="button equal"
data-set="="
aria-label="๊ณ์ฐํ๊ธฐ"
title="๊ณ์ฐํ๊ธฐ"
>
<span class="button__inner">=</span>
</button>
</div>
</div>
<div class="calc-shadow" aria-hidden="true"></div>
</main>
<script src="./src/script.js"></script>
</body>
</html>
/* reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
font-family: "Pretendard", sans-serif;
background-color: var(--black);
}
button {
border: none;
background: none;
padding: 0;
cursor: pointer;
}
/* color variables */
:root {
--white: #ffffff;
--gray-100: #eeeeee;
--gray-200: #dadada;
--gray-300: #b8b8b8;
--gray-400: #444444;
--gray-600: #666666;
--gray-700: #777777;
--gray-800: #8c8c8c;
--black: #222222;
/* status color */
--red: #ff5f57;
--yellow: #ffbd2e;
--green: #28c840;
}
/* calculator-layout */
.calculator {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.calc-container {
position: relative;
display: flex;
flex-direction: column;
gap: 20px;
padding: 20px;
border-radius: 8px;
border: 2px solid var(--white);
background-color: var(--gray-100);
z-index: 100;
}
.calc-shadow {
position: absolute;
bottom: 136px;
width: 384px;
height: 30px;
background: var(--gray-300);
border-radius: 0 0 12px 12px;
background: linear-gradient(180deg, var(--gray-400) -20%, var(--gray-700) 90%);
}
/* calculator inner */
/* window buttons */
.calc__window-btns {
display: flex;
gap: 8px;
}
.calc__window-btn {
width: 20px;
height: 20px;
border-radius: 50%;
background-position: center;
background-repeat: no-repeat;
background-size: 16px;
background-color: var(--gray-600);
transition: all 0.2s ease;
}
.calc__window-btn.close:hover {
background-color: var(--red);
background-image: url(./images/ico_close.svg);
}
.calc__window-btn.min:hover {
background-color: var(--yellow);
background-image: url(./images/ico_min.svg);
}
.calc__window-btn.max:hover {
background-color: var(--green);
background-image: url(./images/ico_max.svg);
}
/* display */
.calc__display {
width: 340px;
height: 88px;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 20px;
font-size: 32px;
border-radius: 8px;
color: var(--gray-100);
background-color: var(--black);
transition: font-size 0.2s ease;
}
/* buttons */
.calc__buttons {
width: 100%;
max-width: 340px;
display: flex;
flex-wrap: wrap;
gap: 4px;
border-radius: 8px;
padding: 4px;
background-color: var(--black);
}
.button {
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
color: var(--gray-600);
padding: 20px;
border-radius: 4px;
background-color: var(--gray-200);
transition: all 0.2s ease;
}
.button__inner {
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
font-size: 18px;
border-radius: 50%;
background: linear-gradient(150deg, var(--gray-300) 20%, var(--gray-100) 60%);
}
.button.zero {
flex-grow: 1;
}
.button:hover {
background-color: var(--gray-300);
}
.button:active {
transform: scale(0.9);
background-color: var(--gray-800);
box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.4);
}
/* utils */
.a11y-hidden {
position: absolute;
overflow: hidden;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
clip: rect(0, 0, 0, 0);
clip-path: inset(50%);
white-space: nowrap;
}
// DOM ์์ (์ ์ญ)
const calcButtons = document.querySelectorAll(".button"); // ๊ณ์ฐ๊ธฐ ๋ฒํผ๋ค
const calcDisplay = document.querySelector(".calc__display"); // ๊ณ์ฐ๊ธฐ ํ๋ฉด
// ๊ณ์ฐ๊ธฐ ์ํ ๋ณ์ (์ ์ญ)
let firstOperand = null; // ์ฒซ ๋ฒ์งธ ํผ์ฐ์ฐ์
let secondOperand = null; // ๋ ๋ฒ์งธ ํผ์ฐ์ฐ์
let operator = null; // ์ฐ์ฐ์
let shouldResetDisplay = false; // ์ ์ซ์ ์
๋ ฅ ์, ๋์คํ๋ ์ด ์ด๊ธฐํ ์ฌ๋ถ
// ์๋ฌ
const isNotDefined = "์ ์๋์ง ์์";
// isNotDefined ์ฒดํฌ ํจ์
const checkNaN = () => {
calcDisplay.textContent = isNotDefined;
firstOperand = null;
secondOperand = null;
operator = null;
shouldResetDisplay = true;
};
// display์ ๊ธ์ ์์ ๋ฐ๋ผ ํฐํธ ํฌ๊ธฐ ์ค์ด๋ ํจ์ (๋จ, ์
๋ ฅ ์ ํ์ ์์)
const adjustDisplayFontSize = () => {
const displayTextLength = calcDisplay.textContent.length;
if (displayTextLength <= 14) {
calcDisplay.style.fontSize = "";
} else if (displayTextLength <= 20) {
calcDisplay.style.fontSize = "22px";
} else if (displayTextLength <= 26) {
calcDisplay.style.fontSize = "18px";
} else {
calcDisplay.style.fontSize = "12px";
}
};
// ์ด๊ธฐํ(C) ๋ฒํผ ํด๋ฆญ ์: ๊ณ์ฐ๊ธฐ ์ํ ๋ณ์ ์ด๊ธฐํ
const clickClear = () => {
firstOperand = null;
secondOperand = null;
operator = null;
shouldResetDisplay = false;
calcDisplay.textContent = "0";
adjustDisplayFontSize();
};
// ์ซ์ ๋ฒํผ ํด๋ฆญ ์
const clickNumber = (number) => {
const currentDisplay = calcDisplay.textContent.trim();
// ์ฐ์ฐ์ ๋ฒํผ์ ๋๋ฅธ ์ดํ๊ฑฐ๋(true), ํ์ฌ ๋์คํ๋ ์ด๊ฐ "0"์ด๋ฉด ์ ์ซ์๋ก ๋ฐ์
if (shouldResetDisplay || currentDisplay === "0") {
calcDisplay.textContent = number;
shouldResetDisplay = false;
} else {
// ์ด์ด์ ์ซ์ ์
๋ ฅ
calcDisplay.textContent += number;
}
adjustDisplayFontSize();
};
// ์์์ ๋ฒํผ ํด๋ฆญ ์
const clickDecimal = () => {
const currentDisplay = calcDisplay.textContent.trim();
if (currentDisplay === isNotDefined) {
clickClear();
}
if (shouldResetDisplay) {
// ์ฐ์ฐ์ ๋ค์, ์ ์ซ์๋ฅผ ์์ํ๋ ๊ฒฝ์ฐ "0."๋ถํฐ ์์
calcDisplay.textContent = "0.";
shouldResetDisplay = false;
} else if (!currentDisplay.includes(".")) {
// ์์์ ์์ผ๋ฉด ์ถ๊ฐ
calcDisplay.textContent += ".";
}
adjustDisplayFontSize();
};
// ์ฐ์ฐ์ ๋ฒํผ ํด๋ฆญ ์
const clickOperator = (value) => {
let currentDisplay = calcDisplay.textContent.trim();
// ํ๋ฉด์ "์ ์๋์ง ์์"์ด๋ฉด clickClear() ํธ์ถ ํ 0๋ถํฐ ์์
if (currentDisplay === isNotDefined) {
clickClear();
currentDisplay = "0";
}
if (firstOperand === null) {
firstOperand = currentDisplay; // ์ฒซ ๋ฒ์งธ ํผ์ฐ์ฐ์๊ฐ null์ด๋ฉด ํ์ฌ ๊ฐ์ ์ ์ฅ
} else if (operator && !shouldResetDisplay) {
secondOperand = currentDisplay; // ๊ธฐ์กด ์ฐ์ฐ์๊ฐ ์๊ณ , ์ ์ซ์ ์
๋ ฅ์ด ์๋ค๋ฉด ๊ณ์ฐ ์งํ
const result = calculate(firstOperand, operator, secondOperand);
if (result === isNotDefined) {
checkNaN();
return;
}
calcDisplay.textContent = String(result); // ํ๋ฉด ์ถ๋ ฅ ์ ์ซ์ -> ๋ฌธ์์ด๋ก ๋ณ๊ฒฝ
firstOperand = result; // ๊ณ์ฐ ๊ฒฐ๊ณผ ๋ค์ ๊ณ์ฐ์ ์ฒซ ๋ฒ์งธ ์ซ์๋ก ์ ์ฅ
}
operator = value; // ํด๋ฆญํ ์ฐ์ฐ๊ธฐํธ ์ ์ฅ
shouldResetDisplay = true; // ์๋ก์ด ์ซ์ ์
๋ ฅ -> display ์ด๊ธฐํ ์ํ ๋ณ๊ฒฝ
console.log(`firstOperand: ${firstOperand}, operator: ${operator}`);
};
// = ๋ฒํผ ํด๋ฆญ ์
const clickEqual = () => {
// ์ฒซ ๋ฒ์งธ ํผ์ฐ์ฐ์์ ์ฐ์ฐ์๊ฐ null์ด ์๋๋ฉด
if (firstOperand !== null && operator !== null) {
secondOperand = calcDisplay.textContent.trim(); // ํ์ฌ ๊ฐ์ ๋ฃ๊ณ calculate() ์คํ
const result = calculate(firstOperand, operator, secondOperand);
// NaN ์๋ฌ ํ์ธ
if (result === isNotDefined) {
checkNaN();
return;
}
calcDisplay.textContent = String(result); // ํ๋ฉด ์ถ๋ ฅ ์ ์ซ์ -> ๋ฌธ์์ด๋ก ๋ณ๊ฒฝ
adjustDisplayFontSize();
// ์ฒซ ๋ฒ์งธ ํผ์ฐ์ฐ์์ ๋ค์ ๊ณ์ฐ์ ์ด์ด๊ฐ๋๋ก ๊ฒฐ๊ณผ ์ ์ฅ
firstOperand = result;
secondOperand = null;
shouldResetDisplay = true;
}
};
// function ๋ฒํผ ํด๋ฆญ ์
const clickFunction = (funcValue) => {
const currentDisplay = calcDisplay.textContent.trim();
let result;
switch (funcValue) {
case "C": // ๋ณ๋ ์ด๊ธฐํ ํจ์(clickClear) ํธ์ถ
return clickClear();
case "ยฑ": // ํ์ฌ ์ซ์์ ๋ถํธ ์ ํ
result = parseFloat(currentDisplay) * -1;
break;
case "%":
const currentNum = parseFloat(currentDisplay);
// ์ฒซ ๋ฒ์งธ ํผ์ฐ์ฐ์์ ์ฐ์ฐ์๊ฐ null์ด ์๋๋ฉด, ์ฆ ํผ์ฐ์ฐ์์ ์ฐ์ฐ์๊ฐ ์์ผ๋ฉด
if (firstOperand !== null && operator !== null) {
const firstNum = parseFloat(firstOperand);
switch (operator) {
case "+":
result = (firstNum * currentNum) / 100;
break;
case "-":
result = (firstNum * currentNum) / 100;
break;
case "*":
result = currentNum / 100;
break;
case "/":
result = currentNum / 100;
break;
}
secondOperand = result;
calcDisplay.textContent = String(result);
adjustDisplayFontSize();
return;
} else {
// ์ฐ์ฐ์ ์๋ ๊ฒฝ์ฐ
result = currentNum / 100;
secondOperand = result;
calcDisplay.textContent = String(result);
return;
}
default:
return; // ์ ์๋์ง ์์ ๊ธฐ๋ฅ ๊ณ ๋ ค
}
calcDisplay.textContent = String(result);
adjustDisplayFontSize();
};
// calculate ํจ์: ์ฐ์ฐ์์ ๋ฐ๋ผ ๊ณ์ฐ ๊ฒฐ๊ณผ ๋ฐํ
const calculate = (firstOperand, operator, secondOperand) => {
// ๋ฌธ์์ด์ ๋ถ๋์์์ ์ซ์๋ก ๋ณํ
const firstNum = parseFloat(firstOperand);
const secondNum = parseFloat(secondOperand);
// ํผ ์ฐ์ฐ์๋ค ์ค ํ๋๋ผ๋ NaN๋ฉด "์ ์๋์ง ์์ ์ฒ๋ฆฌ"
if (isNaN(firstNum) || isNaN(secondNum)) return isNotDefined;
// ์ฐ์ฐ ์กฐ๊ฑด๋ฌธ
switch (operator) {
case "+":
return firstNum + secondNum;
case "-":
return firstNum - secondNum;
case "*":
return firstNum * secondNum;
case "/":
if (secondNum !== 0) {
return firstNum / secondNum;
} else {
// secondNum์ด 0์ด๋ฉด '์ ์๋์ง ์์' ์ถ๋ ฅ (๋ ํผ๋ฐ์ค: ๋งฅ๋ถ ๊ณ์ฐ๊ธฐ)
// ์ดํ ์ฐ์ฐ์, ์ซ์ ์
๋ ฅ ์ Nan ๋ฐํ ์ด์๋ก ๊ฐ์
return isNotDefined;
}
default:
return secondNum; // ์ ์๋์ง ์์ ์ฐ์ฐ์ ๊ณ ๋ ค
}
};
// ๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ
const btnClick = (event) => {
// ํด๋ฆญ๋ ๋ฒํผ ์์ ๋ฐ ๊ฐ
const clickedBtn = event.currentTarget; // ํด๋ฆญํ ๋ฒํผ
const clickedBtnValue = clickedBtn.dataset.set; // ๋ฒํผ์ ์ค์ ๋ ๋ฐ์ดํฐ ๊ฐ (html data-set)
// ๋ฒํผ ํด๋์ค์ ๋ฐ๋ผ ํจ์ ํธ์ถ
if (clickedBtn.classList.contains("clear")) return clickClear();
if (clickedBtn.classList.contains("number")) return clickNumber(clickedBtnValue);
if (clickedBtn.classList.contains("decimal")) return clickDecimal();
if (clickedBtn.classList.contains("operator")) return clickOperator(clickedBtnValue);
if (clickedBtn.classList.contains("equal")) return clickEqual();
if (clickedBtn.classList.contains("function")) return clickFunction(clickedBtnValue);
};
// ๊ณ์ฐ๊ธฐ ๋ฒํผ์ ํด๋ฆญ ์ด๋ฒคํธ ๋ฑ๋ก
calcButtons.forEach((button) => {
button.addEventListener("click", btnClick);
});
// ๐ ๋๋ฒ๊น
์ฉ ์ถ๋ ฅ
// console.log(calcButtons);
// ๊ณ์ฐ๊ธฐ ๋ฒํผ(.button)์ ๋ชจ๋ ์ ํํ๋ฉด NodeList๊ฐ ๋ฐํ๋จ
// NodeList๋ ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ง๋ง, forEach() ๋ฉ์๋๊ฐ ์์ด์ ์ํ ๊ฐ๋ฅ
Git & GitHub โ
Day 21
Git & GitHub 1
Day 22
Git & GitHub 2
React โ
๐ฉ๐ปโ๐ป StackBlitz Collections