본문 바로가기
Side Project

HTML, CSS, JavaScript로 To Do List 만들기 - JavaScript로 기능 구현하기

by Brilliant_Graphite 2024. 7. 7.
const cellNo = createTableCell(taskCount.toString());
const cellContent = createTableCell(taskContent);
const cellDone = createTableCell('');
const cellDelete = createTableCell('');​
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>To Do List</title>
    <link rel="stylesheet" href="ToDoList.css">
</head>
<body>
    <h2 id="title">To Do List</h2>
    <div id="inputSection">
        <label for="plan">
            <input type="text" id="plan" placeholder="Enter your task">
        </label>
        <input type="button" id="submit" value="Add Task">
        <input type="button" id="reset" value="Reset">
    </div>
    <table id="emptyTable">
        <thead>
            <tr>
                <th>No</th>
                <th>Content</th>
                <th>Done</th>
                <th>Delete</th>
            </tr>
        </thead>
        <tbody id="tableBody">
            <!-- Tasks will be dynamically added here -->
        </tbody>
    </table>

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

 

HTML 코드와 요구사항 분석(?)을 해보자면 원하는 기능을 만들 때 사용할 HTML 요소는

 

입력 칸 : plan

입력 버튼 : submit

리셋 버튼 : reset

생성될 테이블 : tableBody

 

이렇게 4개가 있습니다.

 

document.addEventListener('DOMContentLoaded', () => { });

 

이렇게 전체적인 이벤트 리스너를 만들어줍니다.

 

const planInput = document.getElementById('plan');
const submitButton = document.getElementById('submit');
const resetButton = document.getElementById('reset');
const tableBody = document.getElementById('tableBody');

 

그 다음 앞서 말한 요소들을 받아옵니다. 

planInput << plan

submitButton << submit

resetButton << reset

tableBody << tableBody

 

 submitButton.addEventListener('click', () => { });

submitButton을 클릭했을 때 일어나는 일들을 구현하기 위해 껍데기를 만들줍니다. 

 

let taskCount = 0; // To keep track of the task number

submitButton을 누를 때마다 행 번호가 추가되는 거니 임의의 변수를 하나 만들어줍니다. 

 

const taskContent = planInput.value.trim(); // Get the trimmed value from input

양쪽 공백을 제거한 planInput값을 taskContent에 넣습니다. 이제부터 planInput은 taskContent가 되었습니다.

 

 

이제 다른 기능들을 만들어줄  함수 껍데기를 만들어 줍니다.

   // 만들어 놓은 투두리스트를 한 번에 지우는 기능
   function resetButton.addEventListener('click', () => {
       
    });
   
   //  새로운 테이블 칸을 만드는 기능
   function createTableCell() {
       
    }
    
   // 새로운 버튼을 만드는 기능
    function createButton() {
       
    }
    
    // Done 버튼을 만들고 나서 발생하는 효과, toggle을 사용하는 이유는 켰다 껏다 반복할 수 있는게 더 좋아서
     function toggleDone() {
        
    }

 

1. 

SubimtButton 누르면 해줄 기능을 만들어봅시다.

 if (taskContent !== '') {
            taskCount++; // Increment task number

            // Create new row
            const newRow = document.createElement('tr');

            
        }

 

만약 입력 칸이 공백이 아니라면

taskCount++해서 숫자 1부터 시작하게 됩니다. 그리고 새로운 행을 추가합니다.

 

const cellNo = createTableCell(taskCount.toString());
const cellContent = createTableCell(taskContent);
const cellDone = createTableCell('');
const cellDelete = createTableCell('');

 

const cellNo = createTableCell(taskCount.toString());

가져온 숫자 데이터를 문자열로 바꿔서 cellNo에 저장합니다.

const cellContent = createTableCell(taskContent);

가져온 내용을 cellContent에 저장합니다.

const cellDone = createTableCell('');

const cellDelete = createTableCell('');

이곳엔 버튼들을 만들기 위해 공백으로 만듭니다.

 

const doneButton = createButton('✓', 'button-done', () => {
                toggleDone(cellNo, cellContent);
            });
            const deleteButton = createButton('X', 'button-delete', () => {
                tableBody.removeChild(newRow);
            });

 

 

  • doneButton:
    • createButton 함수는 '✓' 기호를 표시하고 'button-done'이라는 클래스를 가진 버튼을 생성합니다.
    • 버튼을 클릭하면 toggleDone(cellNo, cellContent) 함수가 호출됩니다.
    • 이 함수는 나중에 작성할 예정으로, cellNo와 cellContent를 매개변수로 받아 셀의 글자 색을 검은색에서 회색으로 변경하는 기능을 포함할 것입니다.
  • deleteButton:
    • createButton 함수는 'X' 기호를 표시하고 'button-delete'이라는 클래스를 가진 버튼을 생성합니다.
    • 버튼을 클릭하면 tableBody.removeChild(newRow) 함수가 호출되어, newRow라는 생성된 행을 테이블에서 삭제합니다.

 

 // Append cells to row
newRow.appendChild(cellNo);
newRow.appendChild(cellContent);
cellDone.appendChild(doneButton);
newRow.appendChild(cellDone);
cellDelete.appendChild(deleteButton);
newRow.appendChild(cellDelete);

// Append row to table body
tableBody.appendChild(newRow);

 

  • newRow.appendChild(cellNo);: cellNo 셀을 newRow에 추가합니다.
  • newRow.appendChild(cellContent);: cellContent 셀을 newRow에 추가합니다.
  • cellDone.appendChild(doneButton);: doneButton을 cellDone 셀에 추가합니다.
  • newRow.appendChild(cellDone);: cellDone 셀을 newRow에 추가합니다.
  • cellDelete.appendChild(deleteButton);: deleteButton을 cellDelete 셀에 추가합니다.
  • newRow.appendChild(cellDelete);: cellDelete 셀을 newRow에 추가합니다.
  • tableBody.appendChild(newRow);: newRow를 tableBody에 추가하여 테이블 본문에 새로운 행을 삽입합니다.
// Clear input field
planInput.value = '';

 

submitButton을 누르면 planInput에 있던 내용을 다시 초기화 시킵니다.

 

 

2. 

resetButton.addEventListener('click', () => {
        // Clear all tasks
        while (tableBody.firstChild) {
            tableBody.removeChild(tableBody.firstChild);
        }
        taskCount = 0; // Reset task count
    });

리셋 버튼의 이벤트 리스너 입니다. 리셋 버튼을 누르면 제목만 남도록 전부 지웁니다.

 

 

3. 

function createTableCell(text) {
        const cell = document.createElement('td');
        cell.textContent = text;
        return cell;
    }

위에 사용했던 createTableCell의 기능을 구체화합니다. text 문자열 데이터를 새로운 요소인 'td'에 넣어 값을 전달시킵니다.

 

 

4. 

function createButton(text, className, onClick) {
        const button = document.createElement('button');
        button.textContent = text;
        button.classList.add(className);
        button.addEventListener('click', onClick);
        return button;
    }

 

이 함수는 새로운 버튼을 생성하고 설정한 다음 반환하는 역할을 합니다.

 

함수 선언

function createButton(text, className, onClick) {

 

  • createButton이라는 이름의 함수를 정의합니다.
  • 이 함수는 세 개의 매개변수를 받습니다:
    • text: 버튼에 표시될 텍스트
    • className: 버튼에 추가할 CSS 클래스 이름
    • onClick: 버튼을 클릭할 때 실행될 함수 (이벤트 핸들러)

버튼 생성 및 설정

const button = document.createElement('button');

 

 

 

  • document.createElement('button')를 호출하여 새로운 <button> 요소를 생성합니다.
  • 이 생성된 버튼 요소는 button이라는 변수에 저장됩니다.

버튼 텍스트 설정

button.textContent = text;

 

 

 

  • textContent 속성을 사용하여 버튼의 텍스트를 설정합니다.
  • text 매개변수로 전달된 값을 버튼에 표시합니다.

버튼 클래스 추가

button.classList.add(className);

 

 

  • classList의 add 메서드를 사용하여 버튼에 CSS 클래스를 추가합니다.
  • className 매개변수로 전달된 값이 버튼의 클래스 이름으로 설정됩니다. 이를 통해 버튼의 스타일을 지정할 수 있습니다.

클릭 이벤트 리스너 추가

button.addEventListener('click', onClick);

 

 

 

  • addEventListener 메서드를 사용하여 버튼에 클릭 이벤트 리스너를 추가합니다.
  • onClick 매개변수로 전달된 함수가 버튼을 클릭할 때 실행됩니다.

버튼 반환

return button;

 

 

 

최종적으로 설정이 완료된 버튼 요소를 반환합니다.

 

전체적인 설명

이 함수는 다음과 같은 단계를 거쳐 버튼을 생성합니다:

  1. 새로운 <button> 요소를 생성합니다.
  2. 버튼에 표시될 텍스트를 설정합니다.
  3. 버튼에 CSS 클래스를 추가합니다.
  4. 버튼에 클릭 이벤트 리스너를 추가합니다.
  5. 설정이 완료된 버튼 요소를 반환합니다.

5.

function toggleDone(cellNo, cellContent) {
        if (cellContent.style.textDecoration === 'line-through') {
            cellContent.style.textDecoration = 'none';
            cellContent.style.color = 'black';
            cellNo.style.color = 'black'; // Reset first cell color
        } else {
            cellContent.style.textDecoration = 'line-through';
            cellContent.style.color = 'gray';
            cellNo.style.color = 'gray'; // Set first cell color to gray
        }
    }

이 함수는 주어진 셀(cellContent와 cellNo)의 텍스트 스타일을 토글하여, 텍스트가 완료된 항목처럼 보이도록 설정하거나 원래 상태로 되돌립니다.

 

함수 선언

function toggleDone(cellNo, cellContent) {

 

  • toggleDone라는 이름의 함수를 정의합니다.
  • 이 함수는 두 개의 매개변수를 받습니다:
    • cellNo: 행의 첫 번째 셀
    • cellContent: 행의 내용이 있는 셀

완료 상태 토글

if (cellContent.style.textDecoration === 'line-through') {

 

 

 

  • 이 조건문은 cellContent의 textDecoration 스타일 속성이 'line-through'인지 확인합니다.
  • 'line-through'는 텍스트에 취소선을 추가하는 CSS 속성입니다.

완료된 상태 해제

cellContent.style.textDecoration = 'none';
cellContent.style.color = 'black';
cellNo.style.color = 'black'; // Reset first cell color

 

 

 

  • 만약 cellContent의 텍스트가 취소선이 그어져 있다면 ('line-through'), 이를 제거합니다.
  • textDecoration 속성을 'none'으로 설정하여 취소선을 제거합니다.
  • 텍스트 색상을 검은색으로 설정하여 원래 상태로 되돌립니다.
  • cellNo의 색상도 검은색으로 설정하여 첫 번째 셀의 색상을 원래 상태로 되돌립니다.

완료 상태 설정

} else {
    cellContent.style.textDecoration = 'line-through';
    cellContent.style.color = 'gray';
    cellNo.style.color = 'gray'; // Set first cell color to gray
}

 

 

  • 만약 cellContent의 텍스트가 취소선이 그어져 있지 않다면, 취소선을 추가합니다.
  • textDecoration 속성을 'line-through'로 설정하여 텍스트에 취소선을 추가합니다.
  • 텍스트 색상을 회색으로 설정하여 완료된 항목처럼 보이게 합니다.
  • cellNo의 색상도 회색으로 설정하여 첫 번째 셀의 색상을 완료된 항목처럼 보이게 합니다.

 

전체적인 설명

이 함수는 셀(cellNo와 cellContent)의 스타일을 토글하여, 항목이 완료된 것처럼 보이게 하거나 원래 상태로 되돌리는 역할을 합니다.

 

 

 

완성된 코드

document.addEventListener('DOMContentLoaded', () => {
    const planInput = document.getElementById('plan');
    const submitButton = document.getElementById('submit');
    const resetButton = document.getElementById('reset');
    const tableBody = document.getElementById('tableBody');
    let taskCount = 0; // To keep track of the task number

    submitButton.addEventListener('click', () => {
        const taskContent = planInput.value.trim(); // Get the trimmed value from input

        if (taskContent !== '') {
            taskCount++; // Increment task number

            // Create new row
            const newRow = document.createElement('tr');

            // Create cells
            const cellNo = createTableCell(taskCount.toString());
            const cellContent = createTableCell(taskContent);
            const cellDone = createTableCell('');
            const cellDelete = createTableCell('');
            const doneButton = createButton('✓', 'button-done', () => {
                toggleDone(cellNo, cellContent);
            });
            const deleteButton = createButton('X', 'button-delete', () => {
                tableBody.removeChild(newRow);
            });

            // Append cells to row
            newRow.appendChild(cellNo);
            newRow.appendChild(cellContent);
            cellDone.appendChild(doneButton);
            newRow.appendChild(cellDone);
            cellDelete.appendChild(deleteButton);
            newRow.appendChild(cellDelete);

            // Append row to table body
            tableBody.appendChild(newRow);

            // Clear input field
            planInput.value = '';
        }
    });

    resetButton.addEventListener('click', () => {
        // Clear all tasks
        while (tableBody.firstChild) {
            tableBody.removeChild(tableBody.firstChild);
        }
        taskCount = 0; // Reset task count
    });
    

    function createTableCell(text) {
        const cell = document.createElement('td');
        cell.textContent = text;
        return cell;
    }

    function createButton(text, className, onClick) {
        const button = document.createElement('button');
        button.textContent = text;
        button.classList.add(className);
        button.addEventListener('click', onClick);
        return button;
    }

    function toggleDone(cellNo, cellContent) {
        if (cellContent.style.textDecoration === 'line-through') {
            cellContent.style.textDecoration = 'none';
            cellContent.style.color = 'black';
            cellNo.style.color = 'black'; // Reset first cell color
        } else {
            cellContent.style.textDecoration = 'line-through';
            cellContent.style.color = 'gray';
            cellNo.style.color = 'gray'; // Set first cell color to gray
        }
    }
});

 

 

지금까지 구현된 모습

녹화_2024_07_08_16_23_59_886.mp4
0.29MB

 

 

투두 리스트 완성! ;)