티스토리 뷰

목차

  1. 기능정의 및 HTML/CSS
  2. 할 일 추가하기
  3. 할 일 목록에서 할 일 삭제, 완료 처리 구현
  4. 할 일 수정하기
  5. 전체 완료 처리 및 남은 할 일 개수
  6. 하단 버튼 기능 구현

1.  입력에 대한 이벤트 리스너 등록하기

일단 할 일을 추가하기 위해서는 <input> 요소로부터 이벤트 리스너를 등록하여, 이벤트를 캐치 후, 입력받은 데이터를 배열에 순차적으로 담아주어야 합니다.

const todoInputElem = document.querySelector('.todo-input');

let todos = [];
let id = 0;

const init = () => {
    todoInputElem.addEventListener('keypress', (e) =>{
        if( e.key === 'Enter' ){
            appendTodos(e.target.value); todoInputElem.value ='';
        }
    })
}

init()

todos.js 파일을 만들어 줍니다. 그리고  input 요소를 가져오기 위해 querySelector를 사용하여, todoInputElem에 담아두었습니다. todos는 할 일들을 담을 배열입니다. id는 각각의 할 일들이 유니크하게 구별할 수 있는 키값을 설정하기 위해 선언하였습니다. init()함수는 todos.js파일이 실행되자마자 호출되는 함수입니다.

init() 함수는 input요소를 담은 todoInputElem에 'keypress'에 대한 이벤트 리스너를 등록시킵니다. 만약 입력되는 값이 'Enter'라면 appendTodos() 함수에 e.target.value(input의 value)를 넘겨주고, todoInputElem의 value 값을 초기화한다.

2.  할 일 추가하기

todos 배열에 할 일을 추가하는 appendTodos() 함수를 만들었습니다. 할 일은 다음과 같은 타입을 가집니다.

{ id: number;  isCompleted: boolean;  content: string }

  • id : number 타입으로, 할 일의 유니크한 키 값이다.
  • isCompleted :  boolean 타입으로, 할 일의 완료상태를 나타낸다. 
  • content : string 타입으로, 할 일의 내용이다.

newId 변수는 새롭게 저장되는 할일의 id값이며, ++연산자를 통해 1씩 증가시킴으로써 id값이 중복되지 않도록 해줍니다. newTodos는 새롭게 저장될 todos 배열로 getAllTodos() 함수를 통해 이전 todos 배열을 가져온 후, 새롭게 추가된 할 일을 concat()을 통해 추가된 배열을 newTodos에 저장한다. concat()을 사용하는 이유는 concat()은 기존 todos배열에 아무런 영향을 주지 않고 todos배열을 복사한 값에 추가한 할 일을 반환해주기 때문이다. 이렇게 반환된 newTodos를 setTodos()라는 함수로 기존 todos배열을 변경시켜준다.

concat() 말고 다른 방법으로는 스프레드 연산자를 사용해서 다음과 같이 선언할 수 있습니다. 

const newTodos = [ ...getAllTodos(), {id: newId, isCompleted: false, content: text } ] 

let todos = [];
let id = 0;

const setTodos = (newTodos) => {
    todos = newTodos;
}

const getAllTodos = () => {
    return todos;
}

const appendTodos = (text) => {
    const newId = id++;
    const newTodos = getAllTodos().concat({id: newId, isCompleted: false, content: text })
    // 스프레드 연산자 사용할 경우
    // const newTodos = [...getAllTodos(), {id: newId, isCompleted: false, content: text }] 
    setTodos(newTodos)
    paintTodos();
}

3.  HTML에 추가된 할 일 그려주기

할 일이 추가될 때마다, paintTodos() 함수를 실행하여 렌더링합니다. 

<ul class="todo-list">
  // 완료된 일
  <li class="todo-item checked">
    <div class="checkbox">✔</div>
    <div class="todo">첫번째 할 일</div>
    <button class="delBtn">x</button>
  </li>
  // 완료되지 않은 일
  <li class="todo-item">
    <div class="checkbox"></div>
    <div class="todo">두번째 할 일</div>
    <button class="delBtn">x</button>
  </li>
</ul>

paintTodos() 함수를 살펴봅니다. "todo-list" 클래스 네임을 가진 ul 요소를 전역으로 사용하기 위해 querySelector를 사용하여 todoListElem을 전역으로 선언하였습니다. 

paintTodos() 함수에서 가장 먼저 하는 일은 기존의 "todo-list"안에 있는 HTML을 초기화하는 것입니다. 만약 초기화하지 않는다면, paintTodos() 함수를 실행할 때마다, 기존의 HTML이 중복되면서 표현됩니다. 그다음 todos 배열을 가져와 forEach 문을 사용하여, 각 할 일을 "todo-item"에 해당하는 HTML로 만들어서 "todo-list" 요소에 appendChild()를 사용하여 자식 요소로 추가시켜줍니다. todo의 id는 "todo-itme"요소에 setAttribute로 data-id 속성 값으로 지정해서 수정 및 삭제 시 해당 todo를 구분하기 위해 사용한다. 그리고 todo의 isCompleted를 사용하여 해당 todo가 완료된 일인지 아닌지를 판단하여, "todo-list"요소에 "checked"라는 클래스 네임을 더해 CSS를 반영합니다.

const todoListElem = document.querySelector('.todo-list');

const paintTodos = () => {
  todoListElem.innerHTML = ''; //todoListElem 요소 안의 HTML 초기화
  const allTodos = getAllTodos(); // todos 배열 가져오기
  
  // "todo-item"에 해당하는 HTML을 그려서 "todo-list"에 추가하기
  allTodos.forEach(todo => { 
    const todoItemElem = document.createElement('li');
    todoItemElem.classList.add('todo-item');
    
    // todoItemElem.setAttribute('data-id', todo.id );
    const checkboxElem = document.createElement('div');
    checkboxElem.classList.add('checkbox');

    const todoElem = document.createElement('div');
    todoElem.classList.add('todo');
    todoElem.innerText = todo.content;

    const delBtnElem = document.createElement('button');
    delBtnElem.classList.add('delBtn');
    delBtnElem.innerHTML = 'X';

    if(todo.isCompleted) {
      todoItemElem.classList.add('checked');
      checkboxElem.innerText = '✔';
    }

    todoItemElem.appendChild(checkboxElem);
    todoItemElem.appendChild(todoElem);
    todoItemElem.appendChild(delBtnElem);

    todoListElem.appendChild(todoItemElem);
  })
}

 

 

[전체 코드]

const todoInputElem = document.querySelector('.todo-input');
const todoListElem = document.querySelector('.todo-list');

let todos = [];
let id = 0;

const setTodos = (newTodos) => {
    todos = newTodos;
}

const getAllTodos = () => {
    return todos;
}

const appendTodos = (text) => {
    const newId = id++;
    const newTodos = getAllTodos().concat({id: newId, isCompleted: false, content: text })
    // const newTodos = [...getAllTodos(), {id: newId, isCompleted: false, content: text }]
    setTodos(newTodos)
    paintTodos();
}

const paintTodos = () => {
    todoListElem.innerHTML = ''; //todoListElem 요소 안의 HTML 초기화
	const allTodos = getAllTodos() // todos 배열 가져오기

    allTodos.forEach(todo => { 
        const todoItemElem = document.createElement('li');
        todoItemElem.classList.add('todo-item');

        // todoItemElem.setAttribute('data-id', todo.id );

        const checkboxElem = document.createElement('div');
        checkboxElem.classList.add('checkbox');

        const todoElem = document.createElement('div');
        todoElem.classList.add('todo');
        todoElem.innerText = todo.content;

        const delBtnElem = document.createElement('button');
        delBtnElem.classList.add('delBtn');
        delBtnElem.innerHTML = 'X';

        if(todo.isChecked) {
            todoItemElem.classList.add('checked');
            checkboxElem.innerText = '✔';
        }

        todoItemElem.appendChild(checkboxElem);
        todoItemElem.appendChild(todoElem);
        todoItemElem.appendChild(delBtnElem);

        todoListElem.appendChild(todoItemElem);
    })
}

const init = () => {
    todoInputElem.addEventListener('keypress', (e) =>{
        if( e.key === 'Enter' ){
            appendTodos(e.target.value); todoInputElem.value ='';
        }
    })
}

init()

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함