项目实践


TypeScript 项目实践:待办事项应用(Todo App)

本项目是一个简单的待办事项应用,使用 TypeScript 和 React 构建,支持添加、删除和标记待办事项。下面将详细介绍项目的功能、步骤和完整代码。

1. 功能介绍

  • 添加待办事项:用户可以输入待办事项并添加到列表中。
  • 删除待办事项:用户可以删除已完成或不再需要的待办事项。
  • 标记待办事项:用户可以标记待办事项为完成状态。
  • 存储待办事项:使用 Local Storage 保存待办事项,使其在页面刷新后仍然可用。

2. 项目步骤

2.1 创建项目
  1. 初始化项目

    npx create-react-app todo-app --template typescript
    cd todo-app
    
  2. 安装依赖

    npm install uuid
    
2.2 项目结构
todo-app/
├── public/
├── src/
│   ├── components/
│   │   ├── TodoItem.tsx
│   │   └── TodoList.tsx
│   ├── App.tsx
│   ├── index.tsx
│   ├── styles.css
│   └── types.ts
├── package.json
└── tsconfig.json
2.3 创建类型定义

创建 src/types.ts 文件:

export interface Todo {
    id: string;
    text: string;
    completed: boolean;
}
2.4 创建待办事项项组件

创建 src/components/TodoItem.tsx 文件:

import React from 'react';
import { Todo } from '../types';

interface TodoItemProps {
    todo: Todo;
    onToggle: (id: string) => void;
    onDelete: (id: string) => void;
}

const TodoItem: React.FC<TodoItemProps> = ({ todo, onToggle, onDelete }) => {
    return (
        <div style={{ display: 'flex', alignItems: 'center' }}>
            <input
                type="checkbox"
                checked={todo.completed}
                onChange={() => onToggle(todo.id)}
            />
            <span
                style={{
                    textDecoration: todo.completed ? 'line-through' : 'none',
                    marginLeft: '8px',
                }}
            >
                {todo.text}
            </span>
            <button onClick={() => onDelete(todo.id)} style={{ marginLeft: '8px' }}>
                Delete
            </button>
        </div>
    );
};

export default TodoItem;
2.5 创建待办事项列表组件

创建 src/components/TodoList.tsx 文件:

import React from 'react';
import { Todo } from '../types';
import TodoItem from './TodoItem';

interface TodoListProps {
    todos: Todo[];
    onToggle: (id: string) => void;
    onDelete: (id: string) => void;
}

const TodoList: React.FC<TodoListProps> = ({ todos, onToggle, onDelete }) => {
    return (
        <div>
            {todos.map(todo => (
                <TodoItem
                    key={todo.id}
                    todo={todo}
                    onToggle={onToggle}
                    onDelete={onDelete}
                />
            ))}
        </div>
    );
};

export default TodoList;
2.6 创建主应用组件

修改 src/App.tsx 文件:

import React, { useState, useEffect } from 'react';
import { Todo } from './types';
import TodoList from './components/TodoList';

const App: React.FC = () => {
    const [todos, setTodos] = useState<Todo[]>([]);
    const [newTodo, setNewTodo] = useState<string>('');

    useEffect(() => {
        const storedTodos = localStorage.getItem('todos');
        if (storedTodos) {
            setTodos(JSON.parse(storedTodos));
        }
    }, []);

    useEffect(() => {
        localStorage.setItem('todos', JSON.stringify(todos));
    }, [todos]);

    const addTodo = () => {
        if (!newTodo) return;

        const todo: Todo = {
            id: Date.now().toString(),
            text: newTodo,
            completed: false,
        };

        setTodos([...todos, todo]);
        setNewTodo('');
    };

    const toggleTodo = (id: string) => {
        setTodos(todos.map(todo => (todo.id === id ? { ...todo, completed: !todo.completed } : todo)));
    };

    const deleteTodo = (id: string) => {
        setTodos(todos.filter(todo => todo.id !== id));
    };

    return (
        <div style={{ padding: '20px' }}>
            <h1>Todo App</h1>
            <input
                type="text"
                value={newTodo}
                onChange={e => setNewTodo(e.target.value)}
                placeholder="Add a new todo"
            />
            <button onClick={addTodo}>Add Todo</button>
            <TodoList todos={todos} onToggle={toggleTodo} onDelete={deleteTodo} />
        </div>
    );
};

export default App;
2.7 添加样式

创建或修改 src/styles.css 文件(可选):

body {
    font-family: Arial, sans-serif;
}

input {
    margin-right: 8px;
}

src/index.tsx 文件中引入样式:

import React from 'react';
import ReactDOM from 'react-dom';
import './styles.css'; // 引入样式
import App from './App';

ReactDOM.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>,
    document.getElementById('root')
);
2.8 运行应用

在项目目录中运行以下命令启动应用:

npm start

3. 项目测试与展示

3.1 使用方式

  • 打开浏览器,访问 http://localhost:3000
  • 在输入框中输入待办事项并点击“Add Todo”按钮。
  • 使用复选框标记待办事项为完成或未完成。
  • 点击“Delete”按钮删除待办事项。
  • 页面刷新后,待办事项会自动从 Local Storage 中恢复。

3.2 代码总结

这个简单的待办事项应用展示了如何使用 TypeScript 和 React 构建一个基本的功能应用。通过管理状态、处理用户输入以及持久化数据,我们实现了一个完整的待办事项管理工具。该项目可以作为更复杂项目的基础,进一步扩展功能,如编辑待办事项、分类、过滤等。

4. 项目扩展

  • 用户认证:可以添加用户注册和登录功能,使用 Firebase 或其他后端服务。
  • 多用户支持:实现多用户的待办事项管理。
  • 拖放功能:使用库如 react-beautiful-dnd 增加拖放排序功能。
  • 样式优化:使用 CSS 框架如 Bootstrap 或 Material-UI 提升用户界面。

以上是完整的 TypeScript 项目实践,适合入门和提升开发者的技能。希望能对你有所帮助!