数据可视化待办清单:用JS打造你的第一个Web应用

发布于:2025-07-30 ⋅ 阅读:(18) ⋅ 点赞:(0)

"学了JavaScript这么久,我居然还在写计算器?" —— 这就像学了三年做菜只会煮方便面。今天,我们要用LocalStorage+数据可视化,开发一个既实用又炫酷的待办事项应用,让你的学习成果真正"看得见"!

一、项目亮点:为什么选择这个项目?

1.1 技能综合训练场

// 本项目涵盖:
- DOM操作(增删改查)
- 事件处理(点击、拖拽)
- 本地存储(LocalStorage)
- 数据可视化(Chart.js)
- 模块化开发(ES6模块)

1.2 最终效果预览

  • ✅ 添加/删除任务

  • ✅ 任务分类管理

  • ✅ 完成状态切换

  • ✅ 数据持久化存储

  • ✅ 可视化统计图表

二、项目骨架:HTML结构设计

2.1 基础结构代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智能待办清单 | 数据可视化版</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="app-container">
        <header class="app-header">
            <h1>我的智能待办</h1>
            <div class="stats-display">
                <span id="completed-count">0</span>/<span id="total-count">0</span>
                <div class="progress-bar"></div>
            </div>
        </header>
        
        <div class="input-area">
            <input type="text" id="task-input" placeholder="添加新任务...">
            <select id="category-select">
                <option value="work">工作</option>
                <option value="study">学习</option>
                <option value="life">生活</option>
            </select>
            <button id="add-btn">+</button>
        </div>
        
        <div class="task-list-container">
            <ul id="task-list"></ul>
        </div>
        
        <div class="visualization-section">
            <canvas id="task-chart"></canvas>
        </div>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script type="module" src="app.js"></script>
</body>
</html>

三、CSS设计:美观实用的界面

3.1 关键样式实现

/* 任务项动画效果 */
.task-item {
    transition: all 0.3s ease;
    transform-origin: left;
}

.task-item-enter {
    opacity: 0;
    transform: scaleX(0);
}

.task-item-enter-active {
    opacity: 1;
    transform: scaleX(1);
}

/* 进度条动态效果 */
.progress-bar {
    height: 5px;
    background: linear-gradient(to right, #4CAF50 var(--progress), #ddd var(--progress));
    transition: --progress 0.5s ease;
}

/* 分类颜色标识 */
.task-item[data-category="work"] {
    border-left: 4px solid #FF5252;
}

.task-item[data-category="study"] {
    border-left: 4px solid #2196F3;
}

.task-item[data-category="life"] {
    border-left: 4px solid #4CAF50;
}

四、JavaScript核心逻辑

4.1 数据管理模块

// storage.js
const STORAGE_KEY = 'todo-vue';

export default {
    fetch() {
        return JSON.parse(localStorage.getItem(STORAGE_KEY) || [];
    },
    save(todos) {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
    }
};

4.2 任务操作模块

// tasks.js
export default {
    addTask(text, category) {
        return {
            id: Date.now(),
            text,
            category,
            completed: false,
            createdAt: new Date()
        };
    },
    
    toggleComplete(todos, id) {
        return todos.map(todo => 
            todo.id === id ? {...todo, completed: !todo.completed} : todo
        );
    },
    
    deleteTask(todos, id) {
        return todos.filter(todo => todo.id !== id);
    }
};

五、数据可视化实现

5.1 图表初始化

// chart.js
import Chart from 'chart.js/auto';

export function initChart(ctx) {
    return new Chart(ctx, {
        type: 'doughnut',
        data: {
            labels: ['工作', '学习', '生活'],
            datasets: [{
                data: [0, 0, 0],
                backgroundColor: [
                    '#FF5252',
                    '#2196F3',
                    '#4CAF50'
                ]
            }]
        },
        options: {
            responsive: true,
            plugins: {
                legend: {
                    position: 'bottom'
                }
            }
        }
    });
}

export function updateChart(chart, todos) {
    const counts = {
        work: 0,
        study: 0,
        life: 0
    };
    
    todos.forEach(todo => {
        counts[todo.category]++;
    });
    
    chart.data.datasets[0].data = [
        counts.work,
        counts.study,
        counts.life
    ];
    
    chart.update();
}

六、主应用逻辑

6.1 应用初始化

// app.js
import storage from './storage.js';
import taskManager from './tasks.js';
import { initChart, updateChart } from './chart.js';

class TodoApp {
    constructor() {
        this.todos = [];
        this.chart = null;
        this.initElements();
        this.initChart();
        this.loadTasks();
        this.bindEvents();
    }
    
    initElements() {
        this.$taskInput = document.getElementById('task-input');
        this.$addBtn = document.getElementById('add-btn');
        this.$categorySelect = document.getElementById('category-select');
        this.$taskList = document.getElementById('task-list');
        this.$completedCount = document.getElementById('completed-count');
        this.$totalCount = document.getElementById('total-count');
        this.$progressBar = document.querySelector('.progress-bar');
    }
    
    initChart() {
        const ctx = document.getElementById('task-chart');
        this.chart = initChart(ctx);
    }
    
    // ...其他方法
}

new TodoApp();

6.2 任务渲染与更新

// app.js 继续
renderTasks() {
    this.$taskList.innerHTML = '';
    
    this.todos.forEach(todo => {
        const $li = document.createElement('li');
        $li.className = `task-item ${todo.completed ? 'completed' : ''}`;
        $li.dataset.id = todo.id;
        $li.dataset.category = todo.category;
        
        $li.innerHTML = `
            <input type="checkbox" ${todo.completed ? 'checked' : ''}>
            <span class="task-text">${todo.text}</span>
            <button class="delete-btn">×</button>
            <span class="task-category">${this.getCategoryName(todo.category)}</span>
        `;
        
        this.$taskList.appendChild($li);
    });
    
    this.updateStats();
    updateChart(this.chart, this.todos);
}

updateStats() {
    const total = this.todos.length;
    const completed = this.todos.filter(todo => todo.completed).length;
    const progress = total > 0 ? (completed / total) * 100 : 0;
    
    this.$completedCount.textContent = completed;
    this.$totalCount.textContent = total;
    this.$progressBar.style.setProperty('--progress', `${progress}%`);
}

七、完整项目开发流程

7.1 分步实现计划

  1. Day 1:基础HTML/CSS框架搭建

  2. Day 2:实现任务添加/删除功能

  3. Day 3:接入LocalStorage持久化

  4. Day 4:添加数据可视化图表

  5. Day 5:优化交互和动画效果

7.2 项目目录结构

todo-app/
├── index.html
├── styles/
│   ├── main.css
│   ├── animations.css
├── js/
│   ├── app.js        # 主入口
│   ├── storage.js    # 数据持久化
│   ├── tasks.js      # 任务管理
│   ├── chart.js      # 可视化模块
├── README.md

八、高级功能扩展

8.1 拖拽排序实现

// 在TodoApp类中添加
setupDragAndDrop() {
    new Sortable(this.$taskList, {
        animation: 150,
        onEnd: () => {
            // 更新任务顺序
            const newTodos = [...this.todos];
            // ...重新排序逻辑
            this.saveTasks(newTodos);
        }
    });
}

8.2 任务搜索过滤

addSearchFunction() {
    const $searchInput = document.createElement('input');
    $searchInput.type = 'text';
    $searchInput.placeholder = '搜索任务...';
    $searchInput.addEventListener('input', (e) => {
        const keyword = e.target.value.toLowerCase();
        const filtered = this.todos.filter(todo => 
            todo.text.toLowerCase().includes(keyword)
        );
        this.renderFilteredTasks(filtered);
    });
    document.querySelector('.input-area').prepend($searchInput);
}

九、项目部署与分享

9.1 使用GitHub Pages

# 初始化Git仓库
git init
git add .
git commit -m "初始提交"

# 创建GitHub仓库并推送
git remote add origin 你的仓库地址
git push -u origin main

# 开启GitHub Pages
# 设置 → Pages → 选择main分支

9.2 添加PWA支持(可选)

// 添加manifest.json
{
  "name": "智能待办清单",
  "short_name": "TodoApp",
  "start_url": ".",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#4CAF50"
}

// 注册Service Worker
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js');
    });
}

结语:从TodoList到全栈开发

这个项目只是起点!尝试添加更多功能:

  • 用户账户系统(Firebase)

  • 多设备同步(WebSocket)

  • 语音添加任务(Web Speech API)

思考题

  1. 如何实现任务到期提醒功能?

  2. 怎样优化大量任务时的性能?

  3. 如何让图表支持时间维度统计?

欢迎在评论区提交你的作品链接,我会挑选最有创意的3个项目进行深度点评!


网站公告

今日签到

点亮在社区的每一天
去签到