[JS] chapter23. Tree UI
๐ Tree UI
๐ ํธ๋ฆฌ๊ตฌ์กฐ
ํ๋ฉด์ ๊ตฌ์ฑํ ๋ ์ฌ๊ท๋ฅผ ์ฌ์ฉํ๋ ๊ฐ์ฅ ๋ํ์ ์ธ ์์
DOM์ ๋ํด ํ์ต ํ ์ค์ต ์งํ
[JS] chapter11. DOM/DOM ๋ค๋ฃจ๊ธฐ(CRUD)
DOM (Document Object Model) HTML ์์๋ฅผ object ์ฒ๋ผ ์กฐ์ํ ์ ์๋ ๋ชจ๋ธ ์ฆ, DOM์ผ๋ก HTML์ ์กฐ์ ๊ฐ๋ฅํ๋ค. HTML์์ JS ํ์ผ์ ์ ์ฉํ๊ธฐ ์ํด -----------------------------------------------------------------------------------
hwantech.tistory.com
์ฌ๊ท์ ๋ํด ํ์ต ํ ์ค์ต ์งํ
[์๊ณ ๋ฆฌ์ฆ] ์ฌ๊ท ํจ์
๐ ์ฌ๊ท ๐์ฌ๊ท์ ์ดํด ์ฌ๊ท : ์๋์ ์๋ฆฌ๋ก ๋๋์๊ฐ๊ฑฐ๋ ๋๋์์ด ๐ ์ฌ๊ท์ ์ฝ๋ function recursion () { console.log("This is") console.log("recursion!") recursion() } recursion() ํจ์? ์๊ธฐ ์์ ์ ๋์์ด ํธ์ถ
hwantech.tistory.com
๐ ํ์ต ๋ชฉํ
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tree View UI</title>
<link href="https://fonts.googleapis.com/css2?family=Do+Hyeon&display=swap" rel="stylesheet">
<link rel="stylesheet" href="test.css">
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="mocha"></div>
<ul id="root"></ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.2.0/mocha.min.js"></script>
<script>
mocha.setup('bdd');
</script>
<script src="./fix_me.js"></script>
<script src="./test/index.test.js"></script>
<script>
mocha.run();
</script>
</body>
</html>
body script ์์ <ul id="root"></ul> ํ์ธ ๊ฐ๋ฅํ๋ค
์ด ๊ตฌ๋ฌธ ์๋์ ์์ ์๋ฆฌ๋จผํธ ์ ๋ ฅ
fix_me.js
// ์ฌ๋ฌ๋ถ๋ค์ด tree-UI๋ฅผ ๋ง๋์
์ผ ํ ๋ฉ๋ดํ์
๋๋ค.
// menu๋ ์์ ํ์ง ์๊ณ , createTreeView ํจ์๋ง ์์ ํ์ธ์.
const menu = [
{
type: 'group',
name: '์๋ฃ',
children: [
{
type: 'group',
name: '์ฝ๋ ๋ธ๋ฃจ',
children: [
{ type: 'item', name: '๋์ดํธ๋ก ์ฝ๋ ๋ธ๋ฃจ' },
{ type: 'item', name: '๋์ฒด ์ฝ๋ ๋ธ๋ฃจ' },
{ type: 'item', name: '์ ์ฃผ ๋น์๋ฆผ ์ฝ๋ ๋ธ๋ฃจ' },
{ type: 'item', name: '์ฝ๋ ๋ธ๋ฃจ' },
],
},
{
type: 'group',
name: 'ํ๋ผํธ์น๋
ธ',
children: [
{ type: 'item', name: '์ ํ ์ฟ ํค ํฌ๋ฆผ ํ๋ผํธ์น๋
ธ' },
{ type: 'item', name: '๋๋ธ ์์คํ๋ ์ ์นฉ ํ๋ผํธ์น๋
ธ' },
{ type: 'item', name: '๋ชจ์นด ํ๋ผํธ์น๋
ธ' },
{ type: 'item', name: 'ํผ์คํ์น์ค ํฌ๋ฆผ ํ๋ผํธ์น๋
ธ' },
],
},
{
type: 'group',
name: '๋ธ๋ ๋๋',
children: [
{ type: 'item', name: '๋ง๊ณ ๋ฐ๋๋ ๋ธ๋ ๋๋' },
{ type: 'item', name: '๋ธ๊ธฐ ์๊ฑฐํธ ๋ธ๋ ๋๋' },
{ type: 'item', name: '์๋ชฝ ์
๋ฒ ๋ธ๋ ๋๋' },
{ type: 'item', name: 'ํผ์น & ๋ ๋ชฌ ๋ธ๋ ๋๋' },
],
},
{
type: 'group',
name: 'ํฐ',
children: [
{ type: 'item', name: '๋ผ์ ํจ์
ํฐ' },
{ type: 'item', name: '๋ฏผํธ ๋ธ๋ ๋ ํฐ' },
{ type: 'item', name: '์์ด์ค ์ ์ค๋ฒ ๋ฆฌ ํฐ' },
{ type: 'item', name: '์์ด์ค ์บ๋ชจ๋ง์ผ ๋ธ๋ ๋ ํฐ' },
],
},
{
type: 'group',
name: '์ฃผ์ค',
children: [
{ type: 'item', name: 'ํ๋ฐฉ์ ์ญ ๊ฐ๋น' },
{ type: 'item', name: 'ํ์ดํ
์ฒญ๊ทค' },
{ type: 'item', name: '๋ธ๊ธฐ์ฃผ์ค' },
{ type: 'item', name: '๋์์ฃผ ํํ' },
],
},
],
},
{
type: 'group',
name: '์์',
children: [
{
type: 'group',
name: '๋นต',
children: [
{ type: 'item', name: 'ํธ๋ฌํ ๋ฏธ๋ ์ค์ฝ' },
{ type: 'item', name: '๋ณด๋ฌ๋ฐค ๋ชฝ๋ธ๋ ๋ฐ๋์ฌ' },
{ type: 'item', name: '๊ณ ์ํ ์น์ฆ ๋ฒ ์ด๊ธ' },
{ type: 'item', name: '๋ฏธ๋ ํด๋์ ์ค์ฝ' },
],
},
{
type: 'group',
name: '์ผ์ดํฌ',
children: [
{ type: 'item', name: '๋ฐ๋น ์๊ทธ ํ๋ฅดํธ' },
{ type: 'item', name: '๋ง์ค์นดํฌ๋ค ํฐ๋ผ๋ฏธ์ ์ผ์ดํฌ' },
{ type: 'item', name: '๋ธ๋ฃจ๋ฒ ๋ฆฌ ์ฟ ํค ์น์ฆ ์ผ์ดํฌ' },
{ type: 'item', name: '๋ถ๋๋ฌ์ด ์ํฌ๋ฆผ ์นด์คํ
๋ผ' },
],
},
{
type: 'group',
name: '์๋์์น',
children: [
{ type: 'item', name: '์ ํ ๊น๋ง๋ฒ ๋ฅด ์๋์์น' },
{ type: 'item', name: 'ํธ๋ฆฌํ ๋จธ์ฌ๋ฃธ ์น์ฆ ์๋์์น' },
{ type: 'item', name: '๋ก์คํธ ์นํจ ์๋ฌ๋ ๋ฐ ๋ฐ์ค' },
{ type: 'item', name: 'B.E.L.T ์๋์์น' },
],
},
{
type: 'group',
name: '๊ณผ์ผ',
children: [
{ type: 'item', name: 'ํ๋ฃจ ํ ์ปต RED' },
{ type: 'item', name: 'ํ๋ผ๋ด ๊ฐ๋ ํธ๋ ์ ค๋ฆฌ' },
],
},
{
type: 'group',
name: '์ค๋ต',
children: [
{ type: 'item', name: '๋ฆฌ์ ๋ธ ์ด์ฝ๋ฆฟ ์ธํธ' },
{ type: 'item', name: '๋ก์คํฐ๋ ์๋ชฌ๋ ์ค ์ด์ฝ๋ฆฟ' },
{ type: 'item', name: '๋ง์นด๋กฑ' },
{ type: 'item', name: '์์ผ๋ฆฌํจ ์บ๋ ํฌ๋ฆฌ์คํ ๋ฏผํธ' },
],
},
{
type: 'group',
name: '์์ด์คํฌ๋ฆผ',
children: [
{ type: 'item', name: '์๋ฐ ์นฉ ์ ๊ธฐ๋ ๋ฐ๋๋ผ ์์ด์คํฌ๋ฆผ' },
{ type: 'item', name: '๋์ธ ์ด์ฝ๋ฆฟ ์ํฌ๊ฐํ ' },
{ type: 'item', name: '๋ฐ๋๋ผ ์ํฌ๊ฐํ ' },
],
},
],
},
{
type: 'group',
name: '๊ตฟ์ฆ',
children: [
{
type: 'group',
name: '๋จธ๊ทธ',
children: [
{ type: 'item', name: '์ฐ๋ฆฌ ํ๊ธ ๋ธ๋ ๋จธ๊ทธ 473ml' },
{ type: 'item', name: '์์ธ ํฌ์ด ๋จธ๊ทธ 355ml' },
{ type: 'item', name: '์คํ๋ฒ
์ค 1ํธ์ ๋จธ๊ทธ 400ml' },
{ type: 'item', name: '์์ธ ์ ์ฃผ ๋ฐ์ด๋จธ๊ทธ ์ธํธ' },
],
},
{
type: 'group',
name: 'ํ
๋ธ๋ฌ',
children: [
{ type: 'item', name: 'SS ๋ถ์ฐ ํฌ์ด ํ
๋ธ๋ฌ 355ml' },
{ type: 'item', name: 'SS ๋ธ๋ ํค๋ฆฌํฐ์ง ์ค๋๋ฆฌ ํ
๋ธ๋ฌ 355ml' },
{ type: 'item', name: 'SS ์์น๋ ์ค๋ฒ ํ
๋ธ๋ฌ 473ml' },
],
},
{
type: 'group',
name: '์
์ธ์ฌ๋ฆฌ',
children: [
{ type: 'item', name: '๋ฆฌ์ ๋ธ ์ค๋ ์ง ์นด๋ ํ๋' },
{ type: 'item', name: '์คํ๋ฒ
์ค 1ํธ์ ์์ฝ๋ฐฑ' },
{ type: 'item', name: '์คํ๋ฒ
์ค 1ํธ์ ๋ฉํ ํ์ฐ์น' },
],
},
],
},
{
type: 'group',
name: '์นด๋',
children: [
{ type: 'item', name: '10000์๊ถ' },
{ type: 'item', name: '30000์๊ถ' },
{ type: 'item', name: '50000์๊ถ' },
{ type: 'item', name: '100000์๊ถ' },
],
},
];
// TODO: createTreeView ํจ์๋ฅผ ์ฌ๊ท(์๊ธฐ ์์ ์ ๊ณ์ ๋ถ๋ฅด๊ฒ ํจ)ํธ์ถํ์ฌ ํ
์คํธ์ผ์ด์ค๋ฅผ ํต๊ณผํ์ธ์.
// GOAL: ์ต์ข
๊ฒฐ๊ณผ๊ฐ resut.html์ ๊ฐ์ ๋ชจ์ต์ผ๋ก ๋์์ผ ํฉ๋๋ค.
const root = document.getElementById('root');
function createTreeView(menu, currentNode) {
// TODO: createTreeView ํจ์๋ฅผ ์์ฑํ์ธ์.
}
createTreeView(menu, root);
menu ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํด tree view๋ฅผ ๊ตฌ์ฑํฉ๋๋ค
โ ul#root ์๋ฆฌ๋จผํธ ์์ ์นดํ
๊ณ ๋ฆฌ(์๋ฃ, ์์, ๊ตฟ์ฆ, ์นด๋)๋ฅผ ๋ ๋๋งํ 4๊ฐ์ li ์๋ฆฌ๋จผํธ๊ฐ ์์ด์ผ ํฉ๋๋ค
for(let i =0; i < menu.length; i++){
const li = document.createElement('li');
...
}
โ ์นดํ
๊ณ ๋ฆฌ(์๋ฃ, ์์, ๊ตฟ์ฆ, ์นด๋) ์๋ฆฌ๋จผํธ ์์๋ ๊ฐ๊ฐ ์์ ๋
ธ๋๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ๊ฐ์ถฐ์ค checkbox๊ฐ ์กด์ฌํด์ผ ํฉ๋๋ค
if(menu[i].children){
const ipnut = document.createElement('input');
input.type = 'checkbox';
}
โ ์๋ฃ, ์์, ๊ตฟ์ฆ, ์นด๋ ์นดํ
๊ณ ๋ฆฌ ์ด๋ฆ(name)์ span ํ๊ทธ๋ก ๊ฐ์ธ์ผ ํฉ๋๋ค
if(menu[i].children){
...
const span = document.createElement('input');
span.textContext = menu[i].name;
}
โ ์์ ๋
ธ๋๊ฐ ์๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ, li ์๋ฆฌ๋จผํธ ์์ ๋จ์ํ ์ด๋ฆ(name)๋ง ํ์ํฉ๋๋ค. (checkbox ๋ฐ span, ul์ ํฌํจํ๋ฉด ์๋ฉ๋๋ค)
if(menup[i].children){
...
}else{
// ์์๋
ธ๋๊ฐ ์์ ๋ ์ด๋ฆ ํ๊ธฐ
li.textContext = menu[i].name;
currentNode.append(li);
}
โ ์์ ๋ ธ๋๊ฐ ์๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ, li ์๋ฆฌ๋จผํธ ์๋์ ์์ ๋ ธ๋๋ฅผ ๋ ๋๋งํ ์๋ก์ด ul์ด ์กด์ฌํด์ผ ํฉ๋๋ค (1)
โ ์์ ๋ ธ๋๊ฐ ์๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ, li ์๋ฆฌ๋จผํธ ์๋์ ์์ ๋ ธ๋๋ฅผ ๋ ๋๋งํ ์๋ก์ด ul์ด ์กด์ฌํด์ผ ํฉ๋๋ค (2)
// ์์ ๋
ธ๋๊ฐ ์๋ ๋ฐ์ดํฐ์ผ ๊ฒฝ์ฐ
// ์์ ๋
ธ๋๋ฅผ ๋ ๋๋งํ ์๋ก์ด ul์ ๋ง๋ ๋ค
if(menu[i].children){
...
const ul = document.createElement('ul')
// ์์ฑ๋ ๋ถ๋ถ๋ค์ li์ ์ฝ์
li.append(input,span,ul);
// root์ ๋ฃ์ด์ค๋ค
currentNode.append(li);
// ์ด๋ ์ฌ๊ทํจ์ ํธ์ถ -> ์์๋
ธ๋๋ฅผ ๋ง๋ค๊ธฐ ์ํด์
createTreeView(menu[i].children, ul);
}
โ type ์์ฑ์ด item์ธ ๊ฐ์ฒด๋ li ํ๊ทธ๋ก name ์์ฑ๊ฐ์ ๊ฐ์ธ์ฃผ์ด์ผ ํฉ๋๋ค
์์ ๋์ผ