Foreword
I am a ballad. The best time to plant trees was ten years ago, followed by now. Today, I will continue to bring you an explanation of original typescript.
Environment configuration
npm init -y yarn add vite -D
Modify page.json configuration port
{ "name": "demo1", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "vite --port 3002" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "vite": "^4.4.9" } }
Directory structure
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ts</title> </head> <body> <div class="app"> <div class="todo-input"> <input type="text" placeholder="Please enter to-do items"> <button>Add</button> </div> <div class="todo-list"></div> </div> <script type="module" src="./src/app.ts"></script> </body> </html>
app.ts
import { ITodoData } from "./typings"; import TodoEvent from "./TodoEvent"; ; ((doc) => { const oInput: HTMLInputElement = document.querySelector('input') as HTMLInputElement const oAddBtn: HTMLElement = document.querySelector('button') as HTMLElement const oTodoList: HTMLElement = document.querySelector('.todo-list') as HTMLElement const todoData: ITodoData[] = [ { id: 1, content: 'geyao', completed: false }, { id: 2, content: 'fangfang', completed: false }, { id: 3, content: 'kang', completed: false } ] const init = (): void => { bindEvent() } function bindEvent(): void { oAddBtn.addEventListener("click", handleAddBtnClick, false) oTodoList.addEventListener("click", handleListClick, false) } function handleAddBtnClick(): void { const val:string=oInput.value.trim() console.log(val,"val is") if(val.length){ const ret= todoEvent.addTodo(<ITodoData>{ id: 4, content: val, completed: false }) if(ret & amp; & amp;ret===1001){ alert("The list already exists") return } oInput.value='' } } function handleListClick(e: MouseEvent): void { const tar = e.target as HTMLElement const tagName = tar.tagName.toLowerCase() if (tagName === 'input' || tagName === 'button') { const id=parseInt(tar.dataset.id as string) switch (tagName) { case 'input': todoEvent.toggleComplete(tar,id) break; case 'button': todoEvent.removeTodo(tar,id) break; default: break; } } } const todoEvent: TodoEvent = new TodoEvent(todoData,oTodoList) init() })(document)
TodoDom.ts
import TodoTemplate from "./TodoTemplate"; import { ITodoData } from "./typings"; import { createItem, findParentNode } from "./utils"; class TodoDom extends TodoTemplate{ private todoWarpper:HTMLElement; constructor(todoWarpper:HTMLElement){ super() this.todoWarpper=todoWarpper } protected initList(todoData:ITodoData[]){ if(todoData.length){ const oFrag:DocumentFragment=document.createDocumentFragment() todoData.map((todo:ITodoData)=>{ const oItem:HTMLElement= createItem("div","todo-item",this.todoView(todo)) // const oItem:HTMLElement=document.createElement("div") // oItem.className='todo-item' // oItem.innerHTML=this.todoView(todo) oFrag.appendChild(oItem) }) this.todoWarpper.appendChild(oFrag) } } protected addItem(todo:ITodoData){ const oItem:HTMLElement= createItem("div","todo-item",this.todoView(todo)) // const oItem:HTMLElement=document.createElement('div'); // oItem.className='todo-item' // oItem.innerHTML=this.todoView(todo) this.todoWarpper.appendChild(oItem) } protected removeItem(target:HTMLElement){ const oParentNode:HTMLElement=findParentNode(target,"todo-item"); oParentNode.remove() } protected changeCompleted(target:HTMLElement,completed:boolean){ const oParentNode:HTMLElement=findParentNode(target,"todo-item"); const oContent:HTMLElement=oParentNode.getElementsByTagName("span")[0] oContent.style.textDecoration=completed?'line-through':"none" } } export default TodoDom
todoEvent.ts
import TodoDom from "./TodoDom"; import { ITodoData } from "./typings"; class TodoEvent extends TodoDom{ private todoData: ITodoData[] constructor(todoData: ITodoData[],todoWarpper:HTMLElement) { super(todoWarpper) this.todoData = todoData this.init() } public addTodo(todo: ITodoData): undefined | number { const _todo: null | ITodoData | undefined = this.todoData.find((item: ITodoData) => item.content===todo.content) console.log(_todo,"_todo is") if (!_todo) { this.todoData.push(todo) this.addItem(todo) return } return 1001 } protected init(){ this.initList(this.todoData) } public removeTodo(target:HTMLElement,id:number):void { this.todoData=this.todoData.filter((todo:ITodoData)=>todo.id!==id) this.removeItem(target) } public toggleComplete(target:HTMLElement,id:number):void { this.todoData=this.todoData.map((todo:ITodoData)=>{ if(todo.id===id){ todo.completed=!todo.completed this.changeCompleted(target,todo.completed) } return todo; }) } } export default TodoEvent
todoTemplate.ts
import { ITodoData } from "./typings"; class TodoTemplate{ protected todoView({id,content,completed}:ITodoData):string{ return ` <input type="checkbox" ${completed}?'checked':'' data-id="${id}"/> <span style="text-decoration":${completed}?'line-through':'none'>${content}</span> <button data-id='${id}'>Delete</button> ` } } export default TodoTemplate
typing.ts
export interface ITodoData{ id: number, content: string, completed:boolean }
utils.ts
import { callbackify } from "util" export function findParentNode(target:HTMLElement,className:string):any{ while(target=target.parentNode as HTMLElement){ if(target.className===className){ return target } } } export function createItem(tagName:string,className:string,todoItem:string):HTMLElement{ const oItem:HTMLElement=document.createElement(tagName) oItem.className=className oItem.innerHTML=todoItem return oItem }
Run results