๐๐ผ 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
Day 24
React๋ฅผ ์ํ Node.js, nvm, npm, npx
Day 25
React-App ์ธํ
, component์ JSX ๋ฌธ๋ฒ ์ดํดํ๊ธฐ
๐ฉ๐ปโ๐ป React 2์ผ์ฐจ
React์ 3๊ฐ์ง ํน์ง๊ณผ ๊ฐ ํน์ง์ ๋ํ ๊ฐ๋จํ ์ค๋ช
- ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ๊ฐ๋ฐ: UI๋ฅผ ๋ ๋ฆฝ์ ์ด๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ ๋จ์๋ก ๋๋์ด ๊ฐ๋ฐํ๋ ๋ฐฉ์
- ์ ์ธ์ ํ๋ก๊ทธ๋๋ฐ: ์ด๋ป๊ฒ(How?)๊ฐ ์๋ ๋ฌด์(What)์ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ณ ์ ํ๋์ง๋ฅผ ์ค์ฌ์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ์
- ๊ฐ์ DOM ์ฌ์ฉ: ์ํ ๋ณํ๊ฐ ๋ฐ์ํ๋ฉด, ๊ฐ์์ DOM ํธ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ ์ด์ ์ํ์ ๋น๊ตํ ํ ์ค์ DOM์๋ ํ์ํ ๋ณ๊ฒฝ๋ง ์ต์ํ์ผ๋ก ์ ์ฉํ๋ค. (์ด๋ฅผ ํตํด ์ฑ๋ฅ์ ์ต์ ํ ํ ์ ์๋ค.)
create-react-app vs Vite ๋น๊ต
๋น๊ต ํญ๋ชฉ | create-react-app | Vite |
---|---|---|
์ด๊ธฐ ๋น๋ ์๋ | ๋๋ฆฌ๋ค | ๋น ๋ฅด๋ค |
๊ฐ๋ฐ ์๋ฒ ์๋ | ๋๋ฆฌ๋ค | ๋น ๋ฅด๋ค |
๋ฒ๋ค ํฌ๊ธฐ | ํฌ๋ค | ์๋ค |
๊ตฌ์ฑ ๋ฐฉ์ | Webpack | Rollup ๊ธฐ๋ฐ |
๊ณต์ ์ง์ ์ฌ๋ถ | ๊ถ์ฅ๋์ง ์์ | ๊ถ์ฅํ๋ ๋ฐฉ์ |
React์์ Create-react-app(CRA)๋ฅผ ์ถ์ฒํ์ง ์๋ ์ด์
: CRA๋ ๋๋ฆฌ๊ณ ์ปค์คํฐ๋ง์ด์ง์ด ๋ถํธํด ํ์ฅ์ฑ์ด ๋จ์ด์ง๋๋ค.
๋ฒ๋ค์ ํฌ๊ธฐ๋ ์ปค์ ๊ท๋ชจ๊ฐ ์ปค์ง์๋ก ๊ด๋ฆฌ๊ฐ ์ด๋ ต์ต๋๋ค.
๋ฐ๋ผ์ ๊ณต์ ์ฌ์ดํธ์์๋ ๊ถ์ฅํ์ง ์์ผ๋ฉฐ, Vite, Next.js ๋ฑ์ ๊ถ์ฅํฉ๋๋ค.
https://create-react-app.dev/docs/getting-started/
ํจ์ํ ์ปดํฌ๋ํธ๊ฐ React์์ ๋ ์ ํธ๋๋ ์ด์
: ํจ์ํ ์ปดํฌ๋ํธ๋ ์์ฑ์ด ๊ฐ๋จํ๊ณ ์ฝ๋๊ฐ ์ง๊ด์ ์
๋๋ค.
React Hook์ ํตํด ์ํ ๊ด๋ฆฌ์ ์๋ช
์ฃผ๊ธฐ ์ฒ๋ฆฌ, ์ฑ๋ฅ ์ต์ ํ๊น์ง ํจ์จ์ ์ผ๋ก ๊ตฌํํ ์ ์์ด ์ ํธ๋ฉ๋๋ค.
React์ ๊ณต์ ๊ถ์ฅ ๋ฐฉ์์ด๊ธฐ๋ ํฉ๋๋ค.
Day 26
JSX, map & filter๋ฅผ ํ์ฉํ ๋ฐ๋ณต ๋ ๋๋ง
๐ฉ๐ปโ๐ป JSX์ ํน์ง ์ดํดํ๊ธฐ
๐ฉ๐ปโ๐ป map & filter๋ฅผ ํ์ฉํ ๋ฐ๋ณต ๋ ๋๋ง
Day 27
state & props, ์นด๋ ๊ฐค๋ฌ๋ฆฌ
๐ฉ๐ปโ๐ป state์ props๋ฅผ ์ฌ์ฉํ์ฌ ์นด์ดํฐ ์ฑ ์์ฑํ๊ธฐ
๐ฉ๐ปโ๐ป ์นด๋ ๊ฐค๋ฌ๋ฆฌ ์์ฑํ๊ธฐ
Day 28
React ์ํ, Todo-App, ์ฅ๋ฐ๊ตฌ๋ ๊ตฌํ
๐ฉ๐ปโ๐ป React ์ํ ๋ณํ ์ฃผ์ ์ฌํญ ์ดํดํ๊ธฐ
๐ฉ๐ปโ๐ป ๋๋ง์ Todo App ๋ง๋ค๊ธฐ
๐ฉ๐ปโ๐ป ์ฅ๋ฐ๊ตฌ๋ ์์ฑํ๊ธฐ
Day 29
React SPA
๐ฉ๐ปโ๐ป ๋๋ฌผ ์ ๋ณด ์ฌ์ดํธ
๐ฉ๐ปโ๐ป ์น ์ฌ์ดํธ ๋ผ์ฐํ
์ฐ๊ฒฐ
๐ฉ๐ปโ๐ป ์ด๋๋ฏผ ํ์ด์ง ์ฐ๊ฒฐ
Day 30
React Hooks
๐ฉ๐ปโ๐ป useEffect๋ฅผ ์ฌ์ฉํ์ฌ ์๋ช
์ฃผ๊ธฐ ์ดํดํ๊ธฐ
๐ฉ๐ปโ๐ป ์ค์๊ฐ ์๊ณ ์ดํ๋ฆฌ์ผ์ด์
์ ์ํ๊ธฐ
Day 31
React Hooks
๐ฉ๐ปโ๐ป useRef๋ฅผ ์ฌ์ฉํ์ฌ ๊ฒ์์ด ๋ฐ์์ค๊ธฐ
๐ฉ๐ปโ๐ป Custom Hooks๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง ๊ฐค๋ฌ๋ฆฌ ๋ง๋ค๊ธฐ
Day 32
React Mini Project_Todo App
Day 33
React ์คํ์ผ๋ง SASS
๐ฉ๐ปโ๐ป SCSS๋ฅผ ์ด์ฉํ์ฌ OZ ํ์ด์ง ๋์์ธํ๊ธฐ
๐ Demo
Day 34
React ์คํ์ผ๋ง Styled-Components
๐ฉ๐ปโ๐ป Styled-Components๋ฅผ ์ด์ฉํ์ฌ OZ ํ์ด์ง ๋์์ธํ๊ธฐ
๐ Demo
Day 35
React ์คํ์ผ๋ง Tailwind CSS
๐ฉ๐ปโ๐ป tailwindcss๋ฅผ ์ด์ฉํ์ฌ OZ ํ์ด์ง ๋์์ธํ๊ธฐ
๐ Demo
๐ฉ๐ปโ๐ป tailwindcss๋ฅผ ์ด์ฉํ์ฌ OZ ํ์ด์ง ๋์์ธํ๊ธฐ
๐ Demo
Day 36
React ์ํ๊ด๋ฆฌ ์ฌํ
๐ฉ๐ปโ๐ป OZ ์นดํ ์ค์ต ๋ณต์ต
- ๋
ธ์
์ ์ถ
Day 37
React ์ํ๊ด๋ฆฌ ์ฌํ, Context API
๐ฉ๐ปโ๐ป Context API๋ฅผ ์ฌ์ฉํ์ฌ OZ์นดํ ์ฝ๋ ๊ฐ์ ํ๊ธฐ
Day 38
React ์ํ๊ด๋ฆฌ ์ฌํ, Redux & Redux-Toolkit, Recoil, Zustand
๐ฉ๐ปโ๐ป Redux์ ์ฌ์ฉํ์ฌ OZ์นดํ ์ฝ๋ ๋ฆฌํฉํ ๋งํ๊ธฐ
๐ฉ๐ปโ๐ป Redux-Toolkit์ ์ฌ์ฉํ์ฌ OZ์นดํ ์ฝ๋ ๋ฆฌํฉํ ๋งํ๊ธฐ
๐ฉ๐ปโ๐ป Recoil๋ก ์ ์ญ ์ํ ๊ด๋ฆฌํ๊ธฐ
๐ฉ๐ปโ๐ป Zustand ๋ก ์ ์ญ ์ํ ๊ด๋ฆฌํ๊ธฐ & ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์๋ ๋ฐ์ํ๊ธฐ
Day 39
React ์ต์ ํ, useCallback, useMemo, React.memo
๐ฉ๐ปโ๐ป useCallback, useMemo, React.memo ์ฌ์ฉํด๋ณด๊ธฐ
Day 40
React ์ต์ ํ, Todolist ์ต์ ํ
Day 41
ํฌ์ผ๋ชฌ ๋๊ฐ ๋ง๋ค๊ธฐ ๋ฏธ๋ํ๋ก์ ํธ(1/2)
Day 42
ํฌ์ผ๋ชฌ ๋๊ฐ ๋ง๋ค๊ธฐ ๋ฏธ๋ํ๋ก์ ํธ(2/2)
Day 43
Next.js
๐ฉ๐ปโ๐ป Next.js ๊ฐ๋
์ ๋ฆฌํ๊ธฐ
- ๋
ธ์
์ ์ถ
Node.js โ
Day 44
Node.js ๊ฐ๋
์ ๋ฆฌํ๊ธฐ
๐ฉ๐ปโ๐ป Node.js ๊ฐ๋
์ ๋ฆฌํ๊ธฐ
- ๋
ธ์
์ ์ถ
Day 45
๋ก๊ทธ์ธ ์น ์๋ฒ ๋ง๋ค๊ธฐ
Day 46
Session์ผ๋ก ์ ์ ์ ๋ณด ๊ด๋ฆฌํ๊ธฐ
Day 47
Token์ผ๋ก ์ ์ ์ ๋ณด ๊ด๋ฆฌํ๊ธฐ
Day 48
OAuth 2.0์ผ๋ก ์์
๋ก๊ทธ์ธ ๊ตฌํ
๐ฉ๐ปโ๐ป OAuth 2.0์ผ๋ก ์์
๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ - (Kakao/Naver/Google)
Database โ
Day 49
๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์, SQL ์ค์ต ํ๊ฒฝ ์๊ฐ
๐ฉ๐ปโ๐ป SQL ๊ณผ์
- ๋
ธ์
์ ์ถ
Day 50
SQL ๊ธฐ์ด ๋ฌธ๋ฒ, ๋ฐ์ดํฐ ๋ชจ๋ธ๋ง ๊ธฐ์ด
๐ฉ๐ปโ๐ป SQL ๊ณผ์
- ๋
ธ์
์ ์ถ
Day 51
SQL๋ก ์ฌ๋ฌ ํ
์ด๋ธ ๋ค๋ฃจ๊ธฐ, ๋ฐ์ดํฐ ๋ชจ๋ธ๋ง ์ฌํ
๐ฉ๐ปโ๐ป SQL ๊ณผ์
- ๋
ธ์
์ ์ถ
Day 52
๋ฐ์ดํฐ ๋ชจ๋ธ๋ง CASE STUDY
๐ฉ๐ปโ๐ป SQL ๊ณผ์
- ๋
ธ์
์ ์ถ
Day 53
์๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ต
๐ฉ๐ปโ๐ป SQL ๊ณผ์
- ๋
ธ์
์ ์ถ
AWS โ
Day 54
AWS์ ๋ํ ์ดํด
๐ฉ๐ปโ๐ป AWS์ ๋ํ ์ดํด
- ๋
ธ์
์ ์ถ
Day 55
S3์ CloudFront๋ฅผ ์ด์ฉํ ์ ์ ์น์ฌ์ดํธ ํธ์คํ
๐ฉ๐ปโ๐ป S3์ CloudFront๋ฅผ ์ด์ฉํ ์ ์ ์น์ฌ์ดํธ ํธ์คํ
- ๋
ธ์
์ ์ถ
Day 56
๋๋ฉ์ธ ์ค์ , HTTPS ์ค์
๐ฉ๐ปโ๐ป ๋๋ฉ์ธ ์ค์ , HTTPS ์ค์
- ๋
ธ์
์ ์ถ
Day 57
CI/CD ๊ธฐ๋ณธ ๊ฐ๋
๐ฉ๐ปโ๐ป CI/CD ๊ธฐ๋ณธ ๊ฐ๋
- ๋
ธ์
์ ์ถ
Day 58
ํ์
์์ ํ๋ก์ ํธ ์งํํ๋ ๋ฐฉ์์ผ๋ก ์ค์ต
๐ฉ๐ปโ๐ป ํ์
์์ ํ๋ก์ ํธ ์งํํ๋ ๋ฐฉ์์ผ๋ก ์ค์ต
TypeScript โ
Day 59
TypeScript์ ๋ํด ์์๋ณด๊ธฐ
Day 60
TodoList ๋ฆฌํฉํ ๋ง
๐ฉ๐ปโ๐ป TypeScript์ ๋ค์ํ ํ์
์ฌ์ฉํด๋ณด๊ธฐ
๐ฉ๐ปโ๐ป TodoList ๋ฆฌํฉํ ๋ง ํด๋ณด๊ธฐ