当前位置: 首页 > news >正文

从零打造个人博客静态页面与TodoList应用:前端开发实战指南

前言

在当今数字时代,拥有个人博客和高效的任务管理工具已成为开发者展示自我和提升生产力的标配。本文将带你从零开始,通过纯前端技术实现一个兼具个人博客静态页面和TodoList任务管理功能的综合应用。无论你是前端新手还是希望巩固基础的中级开发者,这个项目都将为你提供宝贵的实战经验。

一、项目概述与设计

1.1 为什么选择这个组合项目?

博客页面和TodoList看似是两个独立的功能,但它们的组合能带来以下优势:

  • 展示与实用结合:博客展示你的技术思考,TodoList管理你的创作任务

  • 技术覆盖面广:涵盖HTML结构设计、CSS布局美化、JavaScript交互逻辑

  • 可扩展性强:为后续添加后端功能(如用户认证、数据持久化)奠定基础

1.2 技术选型

我们选择纯前端实现方案,确保项目轻量且易于部署:

  • 核心三件套:HTML5 + CSS3 + JavaScript (ES6+)

  • CSS框架:使用Tailwind CSS实现快速样式开发(可选)

  • 图标库:Font Awesome或Remix Icon

  • 部署方案:GitHub Pages/Vercel/Netlify

二、博客静态页面开发

2.1 HTML结构设计

<!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><header class="blog-header"><nav><div class="logo">我的技术博客</div><ul class="nav-links"><li><a href="#home">首页</a></li><li><a href="#articles">文章</a></li><li><a href="#projects">项目</a></li><li><a href="#about">关于我</a></li><li><a href="#todo">TodoList</a></li></ul></nav></header><main class="blog-container"><section id="home" class="hero-section"><h1>欢迎来到我的技术博客</h1><p>分享前端开发、算法设计与技术思考</p></section><section id="articles" class="articles-section"><h2>最新文章</h2><div class="article-card"><h3>React Hooks深度解析</h3><p class="meta">发布于2023年5月15日 · 8分钟阅读</p><p>本文将深入探讨React Hooks的工作原理和最佳实践...</p><a href="#" class="read-more">阅读全文</a></div><!-- 更多文章卡片 --></section><section id="projects" class="projects-section"><!-- 项目展示区 --></section></main><footer class="blog-footer"><p>© 2023 我的技术博客. 保留所有权利.</p></footer><script src="script.js"></script>
</body>
</html>

2.2 CSS样式美化

/* 基础样式 */
:root {--primary-color: #3498db;--secondary-color: #2ecc71;--dark-color: #2c3e50;--light-color: #ecf0f1;--danger-color: #e74c3c;
}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;line-height: 1.6;color: #333;margin: 0;padding: 0;
}.blog-header {background-color: var(--dark-color);color: white;padding: 1rem 2rem;position: sticky;top: 0;z-index: 100;
}nav {display: flex;justify-content: space-between;align-items: center;
}.logo {font-size: 1.5rem;font-weight: bold;
}.nav-links {display: flex;list-style: none;gap: 2rem;
}.nav-links a {color: white;text-decoration: none;transition: color 0.3s;
}.nav-links a:hover {color: var(--primary-color);
}/* 响应式设计 */
@media (max-width: 768px) {nav {flex-direction: column;}.nav-links {margin-top: 1rem;gap: 1rem;}
}/* 文章卡片样式 */
.article-card {background: white;border-radius: 8px;box-shadow: 0 2px 5px rgba(0,0,0,0.1);padding: 1.5rem;margin-bottom: 1.5rem;transition: transform 0.3s, box-shadow 0.3s;
}.article-card:hover {transform: translateY(-5px);box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}.meta {color: #7f8c8d;font-size: 0.9rem;
}.read-more {display: inline-block;color: var(--primary-color);text-decoration: none;font-weight: bold;margin-top: 0.5rem;
}.read-more:hover {text-decoration: underline;
}

三、TodoList应用实现

3.1 HTML结构

在博客页面中添加TodoList部分:

<section id="todo" class="todo-section"><h2>任务管理</h2><div class="todo-container"><div class="todo-input"><input type="text" id="todoInput" placeholder="添加新任务..."><button id="addTodoBtn">添加</button></div><div class="todo-filters"><button class="filter-btn active" data-filter="all">全部</button><button class="filter-btn" data-filter="active">待完成</button><button class="filter-btn" data-filter="completed">已完成</button></div><ul id="todoList" class="todo-list"><!-- 任务将通过JavaScript动态添加 --></ul><div class="todo-stats"><span id="remainingCount">0</span> 个任务待完成<button id="clearCompleted" class="clear-btn">清除已完成</button></div></div>
</section>

3.2 JavaScript功能实现

document.addEventListener('DOMContentLoaded', function() {// DOM元素const todoInput = document.getElementById('todoInput');const addTodoBtn = document.getElementById('addTodoBtn');const todoList = document.getElementById('todoList');const filterBtns = document.querySelectorAll('.filter-btn');const remainingCount = document.getElementById('remainingCount');const clearCompletedBtn = document.getElementById('clearCompleted');// 状态管理let todos = JSON.parse(localStorage.getItem('todos')) || [];let currentFilter = 'all';// 初始化renderTodoList();updateRemainingCount();// 事件监听addTodoBtn.addEventListener('click', addTodo);todoInput.addEventListener('keypress', function(e) {if (e.key === 'Enter') addTodo();});clearCompletedBtn.addEventListener('click', clearCompleted);filterBtns.forEach(btn => {btn.addEventListener('click', function() {filterBtns.forEach(b => b.classList.remove('active'));this.classList.add('active');currentFilter = this.dataset.filter;renderTodoList();});});// 功能函数function addTodo() {const text = todoInput.value.trim();if (text) {const newTodo = {id: Date.now(),text,completed: false,createdAt: new Date().toISOString()};todos.unshift(newTodo);saveTodos();renderTodoList();updateRemainingCount();todoInput.value = '';}}function renderTodoList() {todoList.innerHTML = '';const filteredTodos = todos.filter(todo => {if (currentFilter === 'all') return true;if (currentFilter === 'active') return !todo.completed;if (currentFilter === 'completed') return todo.completed;return true;});if (filteredTodos.length === 0) {todoList.innerHTML = '<li class="empty-message">暂无任务</li>';return;}filteredTodos.forEach(todo => {const li = document.createElement('li');li.className = `todo-item ${todo.completed ? 'completed' : ''}`;li.dataset.id = todo.id;li.innerHTML = `<input type="checkbox" ${todo.completed ? 'checked' : ''}><span class="todo-text">${todo.text}</span><button class="delete-btn">×</button><small class="todo-date">${formatDate(todo.createdAt)}</small>`;const checkbox = li.querySelector('input[type="checkbox"]');const deleteBtn = li.querySelector('.delete-btn');checkbox.addEventListener('change', function() {toggleTodoComplete(todo.id);});deleteBtn.addEventListener('click', function() {deleteTodo(todo.id);});todoList.appendChild(li);});}function toggleTodoComplete(id) {todos = todos.map(todo => todo.id === id ? {...todo, completed: !todo.completed} : todo);saveTodos();renderTodoList();updateRemainingCount();}function deleteTodo(id) {todos = todos.filter(todo => todo.id !== id);saveTodos();renderTodoList();updateRemainingCount();}function clearCompleted() {todos = todos.filter(todo => !todo.completed);saveTodos();renderTodoList();}function updateRemainingCount() {const count = todos.filter(todo => !todo.completed).length;remainingCount.textContent = count;}function saveTodos() {localStorage.setItem('todos', JSON.stringify(todos));}function formatDate(dateString) {const options = { year: 'numeric', month: 'short', day: 'numeric' };return new Date(dateString).toLocaleDateString('zh-CN', options);}
});

3.3 TodoList样式补充

/* TodoList 样式 */
.todo-section {background-color: #f8f9fa;padding: 2rem;border-radius: 8px;margin-top: 2rem;
}.todo-container {max-width: 600px;margin: 0 auto;background: white;padding: 1.5rem;border-radius: 8px;box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}.todo-input {display: flex;margin-bottom: 1rem;gap: 0.5rem;
}.todo-input input {flex: 1;padding: 0.75rem;border: 1px solid #ddd;border-radius: 4px;font-size: 1rem;
}.todo-input button {padding: 0.75rem 1.5rem;background-color: var(--primary-color);color: white;border: none;border-radius: 4px;cursor: pointer;transition: background-color 0.3s;
}.todo-input button:hover {background-color: #2980b9;
}.todo-filters {display: flex;gap: 0.5rem;margin-bottom: 1rem;
}.filter-btn {padding: 0.5rem 1rem;background: none;border: 1px solid #ddd;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}.filter-btn.active {background-color: var(--primary-color);color: white;border-color: var(--primary-color);
}.todo-list {list-style: none;padding: 0;margin: 0;
}.todo-item {display: flex;align-items: center;padding: 0.75rem;border-bottom: 1px solid #eee;gap: 0.75rem;
}.todo-item.completed .todo-text {text-decoration: line-through;color: #95a5a6;
}.todo-item input[type="checkbox"] {cursor: pointer;
}.todo-text {flex: 1;
}.delete-btn {background: none;border: none;color: var(--danger-color);font-size: 1.25rem;cursor: pointer;opacity: 0.7;transition: opacity 0.3s;
}.delete-btn:hover {opacity: 1;
}.todo-date {color: #95a5a6;font-size: 0.8rem;
}.empty-message {text-align: center;color: #95a5a6;padding: 1rem;
}.todo-stats {display: flex;justify-content: space-between;align-items: center;margin-top: 1rem;color: #7f8c8d;font-size: 0.9rem;
}.clear-btn {background: none;border: none;color: var(--danger-color);cursor: pointer;font-size: 0.9rem;
}.clear-btn:hover {text-decoration: underline;
}

四、项目优化与高级功能

4.1 性能优化建议

  1. 图片懒加载:对博客中的图片实现懒加载

<img src="placeholder.jpg" data-src="actual-image.jpg" class="lazy-load">

// 实现懒加载
const lazyImages = document.querySelectorAll('.lazy-load');const imageObserver = new IntersectionObserver((entries, observer) => {entries.forEach(entry => {if (entry.isIntersecting) {const img = entry.target;img.src = img.dataset.src;img.classList.remove('lazy-load');observer.unobserve(img);}});
});lazyImages.forEach(img => imageObserver.observe(img));

    2. 防抖处理:对搜索功能或频繁触发的事件添加防抖

function debounce(func, delay) {let timeoutId;return function(...args) {clearTimeout(timeoutId);timeoutId = setTimeout(() => {func.apply(this, args);}, delay);};
}// 使用示例
searchInput.addEventListener('input', debounce(function() {// 搜索逻辑
}, 300));

4.2 可添加的高级功能

  1. Markdown支持:让博客支持Markdown格式

// 使用marked.js库
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>// 转换Markdown为HTML
document.getElementById('markdown-content').innerHTML = marked.parse(markdownText);

   2. 主题切换:实现暗黑/明亮模式切换

/* 在:root中添加CSS变量 */
:root {--bg-color: #ffffff;--text-color: #333333;/* 其他变量 */
}/* 暗黑模式 */
[data-theme="dark"] {--bg-color: #1a1a1a;--text-color: #f0f0f0;/* 其他变量 */
}
// 切换主题
function toggleTheme() {const currentTheme = document.documentElement.getAttribute('data-theme');const newTheme = currentTheme === 'dark' ? 'light' : 'dark';document.documentElement.setAttribute('data-theme', newTheme);localStorage.setItem('theme', newTheme);
}// 初始化主题
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);

  3. PWA支持:让应用可离线使用

  • 创建manifest.json文件

  • 注册Service Worker

五、项目部署指南

5.1 GitHub Pages部署

  1. 在GitHub创建新仓库

  2. 将项目代码推送到仓库

  3. 进入仓库Settings > Pages

  4. 选择部署分支(通常是main或master)

  5. 等待几分钟,访问提供的URL

5.2 Vercel部署(更推荐)

  1. 注册Vercel账号(可使用GitHub账号登录)

  2. 点击"New Project"

  3. 导入你的GitHub仓库

  4. 配置项目(保持默认即可)

  5. 点击"Deploy"

  6. 部署完成后会自动获得一个vercel.app的域名

六、总结与扩展方向

通过本项目,你已经掌握了:

  • 响应式博客页面的设计与实现

  • 功能完整的TodoList应用开发

  • 本地存储(localStorage)的使用

  • 前端状态管理的基本概念

  • 项目部署的基本流程

扩展方向建议

  1. 添加后端支持:使用Node.js + Express或Python Flask为项目添加后端API

  2. 数据库集成:使用MongoDB或Firebase存储博客文章和任务数据

  3. 用户认证:实现登录注册功能,让TodoList可以多用户使用

  4. 博客管理系统:开发一个简易的CMS用于管理博客内容

  5. 评论系统:为博客添加

相关文章:

  • 什么是变量提升?
  • C++-缺省参数
  • 菊厂笔试1
  • 电子电器架构 --- 电气/电子架构如何发展以满足其处理和传感器融合需求
  • CAN总线通讯接口卡:工业通信的核心桥梁
  • 在UI原型设计中,低、高保真原型图有什么区别?
  • 验证码(笔记)
  • web 自动化之 Selenium 元素定位和浏览器操作
  • 数据结构 - 10( B- 树 B+ 树 B* 树 4000 字详解 )
  • Node.js 技术原理分析系列9——Node.js addon一文通
  • AI开发跃迁指南(第三章:第四维度1——Milvus、weaviate、redis等向量数据库介绍及对比选型)
  • 腾讯云:数字世界的“量子熔炉”与硅基文明引擎​
  • LeetCode 热题 100 238. 除自身以外数组的乘积
  • 16011.自动分簇KMeans算法
  • element MessageBox 实现底部三个按钮或者更多按钮—开箱即用
  • 【MySQL】第二弹——MySQL表的增删改查(CURD))
  • 【MySQL】存储引擎 - MEMORY详解
  • 使用 CDN 在国内加载本地 PDF 文件并处理批注:PDF.js 5.x 实战指南
  • Ubuntu 安装 Nginx
  • 【hadoop】案例:Sqoop迁移仓库数据
  • 习近平同瑞典国王卡尔十六世·古斯塔夫就中瑞建交75周年互致贺电
  • 多人称华为手机忽现拍照模糊疑存缺陷,售后回应:主摄像头故障
  • 国防部:奉劝有关国家不要引狼入室,甘当棋子
  • 老铺黄金拟配售募资近27亿港元,用于门店拓展扩建及补充流动资金等
  • 联想发布超级智能体矩阵,杨元庆:美国关税影响反映在产品定价上,未来不确定性很大
  • 60岁济南石化设计院党总支书记、应急管理专家李有臣病逝