Vite+React+TypeScript手撸TodoList的项目实践
目录
- 布局与样式
- 创建工程
- 定义全局数据类型
- 实现步骤
- 源码地址
布局与样式
一个TodoList长什么样子相信无需多言:
上样式: src/TodoList.css
.td-wrapper { width: 700px; margin: 0 auto; } .dp-wrapper { width: 100%; height: 40px; display: flex; margin-top: 10px; } .dp-wrapper input { flex: 4; height: 36px; line-height: 36px; text-indent: 10px; font-size: 1rem; } .dp-wrapper button { flex: 1; height: 100%; margin-left: 2px; font-size: 1rem; } .dl-wrapper { border: 1px solid gray; margin-top: 5px; } .dl-wrapper li { height: 40px; line-height: 40px; border-bottom: 1px solid gray; } .dl-wrapper li.done { text-decoration: line-through; } .dl-wrapper li:last-child { border-bottom: none; }
创建工程
npm init vite@latest
后续选择:react + ts 添加必要文件,工程结构如下:
定义全局数据类型
src/vite-env.d.ts
/// <reference types="vite/client" /> /* 代办事项数据结构 */ interface TodoItem { name: string, done: boolean } /* 通用DOM事件处理器 */ type EventHandler = (e?: SyntheticEvent) => void /* 处理函数定义:点击提交按钮 */ type UserInputHandler = (userInput: string, e?: SyntheticEvent) => void /* 处理函数定义:点击列表条目 */ type ImteClickHandler = (index: number, e?: SyntheticEvent) => void /* 获取指定Item的样式名 */ type ItemClassNameGetter = (index: number) => string /* 定义DataPicker组件的Props */ interface DataPickerProps { onUserInput: UserInputHandler } /* 定义DataLister组件的Props */ interface DataListerProps { list: TodoItem[], onItemClick: ImteClickHandler, getClassName: ItemClassNameGetter }
实现步骤
在App.tsx中加载TodoList:
import { useState } from 'react' import './App.css' import TodoList from './TodoList' function App() { return ( <div className="App"> <TodoList></TodoList> </div> ) } export default App
父组件TodoList具体实现: src/TodoList.tsx
import React, { useState } from 'react' import DataLister from './DataLister' import DataPicker from './DataPicker' /* 引入全局样式 */ import "./TodoList.css" export default function TodoList() { /* 定义全局代办事项列表 */ const [todoList, setTodoList] = useState([ { name: "抽中华", done: false }, { name: "喝剑南春", done: false }, { name: "烫杀马特", done: true }, ]) /* 添加代办事项 */ const addTodoItem: UserInputHandler = (userInput: string) => { setTodoList([ { name: userInput, done: false }, ...todoList ]) } /* 切换代办事项完成状态 */ const switchTodoitemState: ImteClickHandler = (index: number) => { setTodoList( todoList.map( (item, i) => ( i !== index ? item : { ...item, done: !item.done } ) ) ) } /* 根据条目完成与否返回不同的样式名 */ const getTodoitemClassName: ItemClassNameGetter = (index: number) => { return todoList[index].done ? "done" : "" } /* 渲染 */ return ( <div className="td-wrapper"> <h3>TodoList</h3> <DataPicker onUserInput={addTodoItem} /> <DataLister list={todoList} onItemClick={switchTodoitemState} getClassName={getTodoitemClassName} /> </div> ) }
用户输入框组件实现: src/DataPicker.tsx
import React, { SyntheticEvent, useState } from 'react' export default function DataPicker({ onUserInput }: DataPickerProps) { /* 定义响应式数据:用户输入的内容 */ const [userInput, setUserInput] = useState("骚年请输入你的闷响...") /* 受控组件的双向数据绑定 */ const onUserInputChange: EventHandler = (e: SyntheticEvent) => { setUserInput((e.target as HTMLInputElement).value) } /* 处理提交按钮点击事件 */ const onSubmit: EventHandler = (e: SyntheticEvent) => { /* 将用户的输入告知父组件,由父组件自行定夺如何处置之 */ onUserInput(userInput) // 清空用户输入 setUserInput("") } /* 渲染 */ return ( <div className='dp-wrapper'> <input type="text" value={userInput} onChange={onUserInputChange} /> <button onClick={onSubmit}>提交</button> </div> ) }
列表展示组件实现: src/DataLister.tsx
export default function DataLister({ list, onItemClick, getClassName }: DataListerProps) { return ( <div className='dl-wrapper'> <ul>{ list.map( (item: TodoItem, index: number) => ( <li key={index + item.name} className={getClassName(index)} onClick={() => { /* 告诉父组件第几个item被点击了 具体如何处置由父元素自行决定 */ onItemClick(index) }}> {item.name} </li> ) ) }</ul> </div> ) }
源码地址
git clone https://gitee.com/steveouyang/todolist-vite-react-ts.git
到此这篇关于Vite+React+TypeScript手撸TodoList的项目实践的文章就介绍到这了,更多相关Vite React TypeScript TodoList内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
赞 (0)