插件窝 干货文章 我在 Typescript 中创建了一个 Todo 应用程序,并将 Todos 保存在本地存储中

我在 Typescript 中创建了一个 Todo 应用程序,并将 Todos 保存在本地存储中

todos todo gt checkbox 480    来源:    2024-10-23

我们使用带有打字稿的普通 vite 项目来理解打字稿,并使用本地存储来存储待办事项。




     <meta charset="utf-8"><link rel="icon" type="image/svg+xml" href="/vite.svg"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>vite + ts</title><link rel="stylesheet" href="./src/style.css"><div id="app">

          <div class="container">

               <h1>my todo list</h1>

          <form id="myform">
               <input required type="text" id="inputtodo" placeholder="enter todo"><button type="submit" id="btnsubmit">add</button>
          </form>

          <div class="todos-container">
               <!-- <div class="todo-item">
                    <input id="iscomplete" type="checkbox">
                    <p id="todotext">my today todo</p>
                    <button id="btndelete">x</button>
               </div> -->
          </div>

     </div>

</div>

     <script type="module" src="/src/main.ts"></script>
.container{
     max-width: 700px;
     margin-inline: auto;
     display: flex;
     align-items: center;
     justify-content: center;
     flex-direction: column;
}

form #inputtodo{
     padding: 8px 15px;
}

form #btnsubmit{
     padding: 8px 15px;
}

.todos-container{
     padding: 10px;
     width: 100%;
     width: fit-content;
}

.todo-item{
     padding: 5px;
     border: 1px solid gray;
     gap: 20px;
     width: 100%;
     display: flex;
     align-items: center;
}

.textcut{
     text-decoration: line-through;
}
interface Todo{
     content: string,
     isComplete: boolean,
     readonly id:string
}

let todos:Todo[] = [];

const todosContainer = document.querySelector('.todos-container')!;

function genrateTodo(id: string, content:string, isComplete:boolean){
     const itemContainer:HTMLDivElement = document.createElement('div');
     itemContainer.classList.add('todo-item');

     // checkbox
     const checkbox: HTMLInputElement = document.createElement('input');
     checkbox.type = "checkbox";
     checkbox.checked = isComplete
     checkbox.onchange = () =&gt; {
          todos.find(todo =&gt; {
               if(todo.id === id) todo.isComplete = checkbox.checked;

               // save updated todo
               localStorage.setItem('todos', JSON.stringify(todos));
          })
          todoText.className = checkbox.checked ? 'textCut' : '';
     }

     // paragraph content
     const todoText:HTMLParagraphElement = document.createElement('p');
     todoText.innerHTML = content;
     todoText.className = isComplete ? 'textCut' : '';

     // delete button
     const btnDelete: HTMLButtonElement = document.createElement('button');
     btnDelete.textContent = 'X';
     btnDelete.onclick = () =&gt; {
          todos = todos.filter(todo =&gt; todo.id !== id);
          localStorage.setItem('todos', JSON.stringify(todos));
          renderTodos(todos);
     }

     itemContainer.append(checkbox, todoText, btnDelete);
     todosContainer.appendChild(itemContainer);

}

// add todo
const form = document.getElementById('myForm')!;
form.onsubmit = (e: SubmitEvent) =&gt; {
     e.preventDefault();
     const inputElement = document.getElementById('inputTodo') as HTMLInputElement;
     let value:string = inputElement.value;

     const newTodo:Todo = {
          id: String(Math.random() * 1000),
          content: value,
          isComplete: false
     }

     todos.push(newTodo);
     inputElement.value = "";

     localStorage.setItem('todos', JSON.stringify(todos));

     renderTodos(todos);
}


function renderTodos(todos: Todo[]){
     todosContainer.innerHTML = "";
     todos.forEach(todo =&gt; {
          genrateTodo(todo.id, todo.content, todo.isComplete);
     })
}

const jsonTodos = localStorage.getItem('todos')!;
const storedTodos : Todo[] = JSON.parse(jsonTodos);
todos = storedTodos;
renderTodos(todos);