ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • HTML+Javascript+CSS ๊ธฐ๋ณธ ์‹ค์Šต
    IT๊ธฐ์ˆ  2025. 3. 24. 08:24

    ๐Ÿง‘‍๐Ÿ’ป ์ฝ”๋“œ ๋ฆฌ๋ทฐ  – To-Do List ํ”„๋กœ์ ํŠธ ์ „์ฒด ์ ๊ฒ€ โœ…๐Ÿ“‹
    ๊ตฌ์„ฑ: HTML + CSS + JS
    ๊ธฐ๋Šฅ: ๊ธฐ๋ณธ์ ์ธ ์ฒดํฌ๋ฐ•์Šค ๊ธฐ๋ฐ˜ ํ•  ์ผ ๋ฆฌ์ŠคํŠธ + ์„ ํƒ ์‚ญ์ œ + ์ „์ฒด ์‚ญ์ œ


    1๏ธโƒฃ HTML ๋ฆฌ๋ทฐ

    <!DOCTYPE html>
    <html lang="ko">
    <head>
      <meta charset="UTF-8">
      <title>To-Do List</title>
      <link rel="stylesheet" href="style.css">
    
    
    </head>
    <body>
      <h1>๐Ÿ“‹ ํ•  ์ผ ๋ฆฌ์ŠคํŠธ</h1>
    
      <div class="input-area">
        <input type="text" id="todoInput" placeholder="ํ•  ์ผ์„ ์ž…๋ ฅํ•˜์„ธ์š”">
        <button onclick="addItem()">โž• ์ถ”๊ฐ€</button>
        <!-- <button onclick="addItem()">โž• ์•„์ดํ…œ ์ถ”๊ฐ€</button> -->
        <button onclick="removeItem()">โŒ ์‚ญ์ œ</button>
        <button onclick="removeAllItem()">โŒ ์ „์ฒด์‚ญ์ œ</button>
      </div>
    
      <ul id="todoList"></ul>
    
      <script src="script.js"></script>
    </body>
    </html>

    โœ… ์žฅ์ 

    • ๊ตฌ์กฐ ๊ฐ„๊ฒฐ, ์‹œ๋งจํ‹ฑ ํƒœ๊ทธ ์‚ฌ์šฉ ์ ์ ˆ (<input>, <button>, <ul>)
    • lang="ko" ๋ฐ charset="UTF-8" ์„ธํŒ… ์™„๋ฒฝ
    • ๋ฒ„ํŠผ ํ…์ŠคํŠธ + ์ด๋ชจ์ง€ ์‚ฌ์šฉ์€ UX ์ธก๋ฉด์—์„œ ์ง๊ด€์  ๐Ÿ‘Œ

    ๐Ÿ”ง ๊ฐœ์„  ์ œ์•ˆ

    ์œ„์น˜ ๊ฐœ์„  ํฌ์ธํŠธ ์ด์œ 

    <button onclick="..."> onclick ๋Œ€์‹  addEventListener๋ฅผ JS์—์„œ ์‚ฌ์šฉ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ, HTML ๋ถ„๋ฆฌ ์›์น™
    <script src="script.js"> defer ์†์„ฑ ์ถ”๊ฐ€ ์ถ”์ฒœ DOM ๋กœ๋“œ ์ดํ›„ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅ (<script defer src="...">)

    2๏ธโƒฃ JS ๋ฆฌ๋ทฐ

    function addItem() {
        const input = document.getElementById("todoInput");
        const text = input.value.trim();
    
        if (text === "") {
            alert("ํ•  ์ผ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”!");
            return;
        }
    
        //์ฒดํฌ๋ฐ•์Šค ์„ ์–ธ
        const checkbox = document.createElement("input");
        checkbox.type = "checkbox";
    
        //๋ฆฌ์ŠคํŠธ
        const list = document.getElementById("todoList");
    
        //๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ
        const item = document.createElement("li");
        //item.textContent = text;
    
        //์•„์ดํ…œ ํ…์ŠคํŠธ
        const textNode = document.createTextNode(" " + text);
    
        // // ํด๋ฆญํ•˜๋ฉด ์‚ญ์ œ
        // item.addEventListener("click", function () {
        //     list.removeChild(item);
        // });
    
        item.appendChild(checkbox);
        item.appendChild(textNode);
        
        list.appendChild(item);
        input.value = "";  // ์ž…๋ ฅ์ฐฝ ์ดˆ๊ธฐํ™”
    }
    
    
    function removeItem() {
        console.log("์‚ญ์ œ ํ•จ์ˆ˜ ์‹คํ–‰๋จ");
        const list = document.getElementById("todoList");
        const items = list.querySelectorAll("li");
    
        items.forEach(item => {
            console.log("์‚ญ์ œ for each๋ฌธ ์‹คํ–‰์ค‘");
            const checkbox = item.querySelector("input[type='checkbox']");
            if (checkbox && checkbox.checked) {
                list.removeChild(item);
            }
        });
    }
    
    
    function removeAllItem() {
        console.log("์ „์ฒด์‚ญ์ œ ํ•จ์ˆ˜ ์‹คํ–‰๋จ");
    
        // 1. UL ๊ฐ€์ ธ์˜ค๊ธฐ
        const list = document.getElementById("todoList");
    
        // ์ „์ฒด Item ์‚ญ์ œ
        while (list.firstChild) {
            list.removeChild(list.firstChild);
        }
    
    
        // // 2. ๋ชจ๋“  ํ•  ์ผ ํ•ญ๋ชฉ(li) ๊ฐ€์ ธ์˜ค๊ธฐ
        // const items = list.querySelectorAll("li");
    
        // // 3. ํ•ญ๋ชฉ๋“ค ํ•˜๋‚˜์”ฉ ํ™•์ธ
        // items.forEach(item => {
        //     console.log("์ „์ฒด์‚ญ์ œ for each๋ฌธ ์‹คํ–‰ ์ค‘.")
        //     const checkbox = item.querySelector("input[type='checkbox']");
    
        //     // 4. ์ฒดํฌ๋˜์–ด ์žˆ์œผ๋ฉด ์‚ญ์ œ
        //     if (checkbox && checkbox.checked) {
        //         list.removeChild(item);
        //     }
        // });
    }
        
    
    
        // // ํด๋ฆญํ•˜๋ฉด ์‚ญ์ œ
        // item.addEventListener("click", function () {
        //     list.removeChild(item);
        // });

    โœ… ๊ธฐ๋Šฅ ๊ตฌํ˜„ ํ›Œ๋ฅญํ•œ ์ 

    • ๊ณต๋ฐฑ ์ž…๋ ฅ ๋ฐฉ์ง€ ๋กœ์ง (trim())
    • ์ฒดํฌ๋ฐ•์Šค ์ƒ์„ฑ ๋ฐ li์— ๋™์  ์ถ”๊ฐ€
    • ์„ ํƒ ์‚ญ์ œ์™€ ์ „์ฒด ์‚ญ์ œ ๋ชจ๋‘ ๋ณ„๋„ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌ ๐Ÿ’ก
    • console.log()๋กœ ๋””๋ฒ„๊น… ํฌ์ธํŠธ ํ™•์ธ ๊ฐ€๋Šฅ

    ๐Ÿ”ง ๊ฐœ์„  ์ œ์•ˆ

    ์œ„์น˜ ๊ฐœ์„  ํฌ์ธํŠธ ์ด์œ 

    onclick="addItem()" ๋“ฑ JS ๋‚ด๋ถ€์—์„œ addEventListener๋ฅผ ํ†ตํ•ด ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๋ฐฉ์‹ ๊ถŒ์žฅ HTML๊ณผ JS ๋ถ„๋ฆฌ, ์žฌ์‚ฌ์šฉ์„ฑ ์ฆ๊ฐ€
    list.removeChild(item) forEach๋กœ ๋ฃจํ”„ ๋Œ๋ฉฐ ์‚ญ์ œํ•  ๊ฒฝ์šฐ, ์—ญ์ˆœ์œผ๋กœ ์ œ๊ฑฐํ•ด์•ผ ์•ˆ์ „ ํ˜„์žฌ๋Š” ์ •์ƒ ์ž‘๋™ํ•˜๋‚˜ DOM ๋ณ€๊ฒฝ ์ค‘ ์ˆœํšŒ๋Š” ๋ฒ„๊ทธ ์œ ๋ฐœ ๊ฐ€๋Šฅ์„ฑ
    checkbox ํƒœ๊ทธ ๋ถ„๋ฆฌ ์„ ์–ธ ๋ณ„๋„ ํ•จ์ˆ˜๋กœ ๋นผ์„œ ์ถ”ํ›„ UI ํ™•์žฅ ๋Œ€๋น„ ์˜ˆ: createTodoItem(text) ๋“ฑ

    ๐Ÿง  ๋ฆฌํŒฉํ† ๋ง ์˜ˆ์‹œ (์ด๋ฒคํŠธ ์—ฐ๊ฒฐ)

    document.addEventListener('DOMContentLoaded', () => {
        document.querySelector('button[onclick="addItem()"]').onclick = addItem;
        document.querySelector('button[onclick="removeItem()"]').onclick = removeItem;
        document.querySelector('button[onclick="removeAllItem()"]').onclick = removeAllItem;
    });
    

    ๋˜๋Š” ์•„์˜ˆ querySelectorAll('button')๋กœ ์ˆœํšŒํ•˜๋ฉฐ data-action ๊ฐ™์€ ์ปค์Šคํ…€ ์†์„ฑ์œผ๋กœ ์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅํ•ด์š”.


    3๏ธโƒฃ CSS ๋ฆฌ๋ทฐ

    body {
        font-family: sans-serif;
        background-color: #f0f0f0;
        padding: 20px;
      }
      
      .input-area {
        margin-bottom: 20px;
      }
      
      input {
        padding: 10px;
        font-size: 16px;
      }
      
      button {
        padding: 10px;
        font-size: 16px;
        margin-left: 5px;
        background-color: #4CAF50;
        color: white;
        border: none;
      }
    
      button:hover{
        background: #66BB6A;
        cursor: pointer;
      }
      
      ul {
        list-style: none;
        padding: 0;
      }
      
      li {
        background: white;
        padding: 10px;
        margin-bottom: 5px;
        cursor: pointer;
        transition: 0.2s;
        
        display: flex;
        align-items: center;
        gap: 8px;
    
      }
      
      li:hover {
        background: #ddd;
      }

    โœ… ๋””์ž์ธ ์žฅ์ 

    • hover, transition, gap, display: flex ํ™œ์šฉ์œผ๋กœ UI ๊น”๋”ํ•จ ๐ŸŽจ
    • ๋ฒ„ํŠผ ์Šคํƒ€์ผ์ด ๋ˆˆ์— ์ž˜ ๋” (์ƒ‰์ƒ ์ผ๊ด€์„ฑ OK)
    • li ํ•ญ๋ชฉ๋„ ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์‘ ์ข‹์Œ (hover ์ƒ‰์ƒ ๋ณ€๊ฒฝ)

    ๐Ÿ”ง ๊ฐœ์„  ์ œ์•ˆ

    ์„ ํƒ์ž ๊ฐœ์„  ํฌ์ธํŠธ ์ด์œ 

    input, button ๊ณตํ†ต์ ์ธ ํŒจ๋”ฉ, ํฐํŠธ ๋“ฑ์€ .input-area * ๋˜๋Š” ๊ณตํ†ต ํด๋ž˜์Šคํ™” ์ถ”์ฒœ CSS ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ํ–ฅ์ƒ
    ๋ฐฐ๊ฒฝ์ƒ‰ #f0f0f0 ๋‹คํฌ ๋ชจ๋“œ ๋Œ€๋น„ ์‹œ :root์— ๋ณ€์ˆ˜๋กœ ์ฒ˜๋ฆฌ ๊ณ ๋ ค ํ™•์žฅ์„ฑ / ํ…Œ๋งˆ ์œ ์—ฐ์„ฑ ํ™•๋ณด
    li:hover ์ปค์„œ ๊ธฐ๋ณธ ์„ค์ • OK์ง€๋งŒ, ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ์—†์œผ๋ฏ€๋กœ pointer ๋ถˆํ•„์š” UX ๋ช…ํ™•์„ฑ

    ๐Ÿ“ฆ ์ข…ํ•ฉ ์ •๋ฆฌ

    ํ•ญ๋ชฉ ํ‰๊ฐ€

    ๊ธฐ๋Šฅ ๊ตฌํ˜„ โœ… ๋งค์šฐ ์ถฉ์‹ค
    UI/UX โœ… ์ง๊ด€์ ์ด๊ณ  ๊น”๋”
    ์œ ์ง€๋ณด์ˆ˜์„ฑ ๐ŸŸก ๊ฐœ์„  ์—ฌ์ง€ ์žˆ์Œ (์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ ๋ฐฉ์‹, ๊ตฌ์กฐ ๋ถ„๋ฆฌ)
    ์„ฑ๋Šฅ/์•ˆ์ •์„ฑ โœ… ํ˜„์žฌ ๊ตฌ์กฐ์—์„œ๋Š” ์ถฉ๋ถ„
    ํ™•์žฅ์„ฑ ๐ŸŸก ์ปดํฌ๋„ŒํŠธํ™”๋‚˜ ํ…œํ”Œ๋ฆฟํ™” ์‹œ๋„ ๊ฐ€๋Šฅ

    ๐Ÿ’ก ๋‹ค์Œ ๋‹จ๊ณ„ ์ถ”์ฒœ

    • โœ… ๊ฐœ๋ณ„ ์•„์ดํ…œ์— ์‚ญ์ œ ๋ฒ„ํŠผ ์ถ”๊ฐ€
    • โœ… localStorage๋กœ ์ €์žฅํ•ด์„œ ์ƒˆ๋กœ๊ณ ์นจ ํ›„์—๋„ ์œ ์ง€๋˜๋„๋ก
    • โœ… ์™„๋ฃŒ ํ•ญ๋ชฉ ์Šคํƒ€์ผ(์ทจ์†Œ์„ , ์ƒ‰์ƒ ๋ณ€๊ฒฝ ๋“ฑ) ์ถ”๊ฐ€
    • ๐Ÿงฉ Vue/React๋กœ ๋ฆฌํŒฉํ† ๋งํ•ด๋ณด๊ธฐ

    ํ•„์š”ํ•˜๋ฉด ์œ„ ์ถ”์ฒœ ๊ธฐ๋Šฅ๋“ค๋„ ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ ๋„์™€์ค„๊ฒŒ์š” ๐Ÿง‘‍๐Ÿ’ป
    ์›ํ•˜๋Š” ๊ธฐ๋Šฅ ํ‚ค์›Œ๋“œ๋งŒ ๋งํ•ด์ค˜!

     

     

     

     

     

Designed by Tistory.