从零打造个人博客静态页面与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. 评论系统:为博客添加

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/80300.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工作流与n8n:自动化技术的演进与开源工具的核心地位

第一章 工作流的基础理论介绍 1.1 工作流的定义与核心要素 工作流&#xff08;Workflow&#xff09;是指一系列相互衔接、自动化的业务活动或任务&#xff0c;其核心在于通过规则驱动的流程设计&#xff0c;实现跨系统、跨角色的协同作业。根据国际工作流管理联盟&#xff08…

WordPress插件:WPJAM Basic优化设置

WPJAM Basic 插件的「优化设置」是我爱水煮鱼博客多年使用 WordPress 的经验而整理的各类优化设置。 一、功能屏蔽 功能屏蔽就是屏蔽一些WordPress中用不上、难用的功能&#xff0c;目前的支持屏蔽以下功能&#xff1a; &#xff08;1&#xff09;屏蔽文章修订功能 文章修…

Spring AI 入门(持续更新)

介绍 Spring AI 是 Spring 项目中一个面向 AI 应用的模块&#xff0c;旨在通过集成开源框架、提供标准化的工具和便捷的开发体验&#xff0c;加速 AI 应用程序的构建和部署。 依赖 <!-- 基于 WebFlux 的响应式 SSE 传输 --> <dependency><groupId>org.spr…

c/c++日志库初识

C/C日志库&#xff1a;从入门到实践的深度指南 在软件开发的世界里&#xff0c;日志&#xff08;Logging&#xff09;扮演着一个沉默却至关重要的角色。它像是飞行记录仪的“黑匣子”&#xff0c;记录着应用程序运行时的关键信息&#xff0c;帮助开发者在问题发生时追溯根源&a…

C 语言图形编程 | 界面 / 动画 / 字符特效

注&#xff1a;本文为 “C 语言图形编程” 相关文章合辑。 略作重排&#xff0c;如有内容异常&#xff0c;请看原文。 C 语言图形化界面——含图形、按钮、鼠标、进度条等部件制作&#xff08;带详细代码、讲解及注释&#xff09; 非线性光学元件于 2020-02-15 09:42:37 发布…

开发狂飙VS稳定刹车:Utility Tree如何让架构决策“快而不失控”

大家好&#xff0c;我是沛哥儿。 在软件技术架构的世界里&#xff0c;架构师们常常面临灵魂拷问&#xff1a;高并发和低成本哪个优先级更高&#xff1f; 功能迭代速度和系统稳定性该如何平衡&#xff1f; 当多个质量属性相互冲突时&#xff0c;该如何做出科学决策&#xff1f; …

SCI论文图数据提取软件——GetData Graph Digitizer

在写综述或者毕业论文的时候一般会引用前人的文献数据图&#xff0c;但是直接截图获取来的数据图通常质量都不太高。因此我们需要从新画一张图&#xff0c;可以通过origin绘图来实现&#xff0c;今天介绍一个新的软件GetData Graph Digitizer 感谢下面博主分享的破解安装教程 …

深入探索 Apache Spark:从初识到集群运行原理

深入探索 Apache Spark&#xff1a;从初识到集群运行原理 在当今大数据时代&#xff0c;数据如同奔涌的河流&#xff0c;蕴藏着巨大的价值。如何高效地处理和分析这些海量数据&#xff0c;成为各行各业关注的焦点。Apache Spark 正是为此而生的强大引擎&#xff0c;它以其卓越…

场景可视化与数据编辑器:构建数据应用情境​

场景可视化是将数据与特定的应用场景相结合&#xff0c;借助数据编辑器对数据进行灵活处理和调整&#xff0c;通过模拟和展示真实场景&#xff0c;使企业能够更直观地理解数据在实际业务中的应用和影响&#xff0c;为企业的决策和运营提供有力支持。它能够将抽象的数据转化为具…

攻防世界-php伪协议和文件包含

fileinclude 可以看到正常回显里面显示lan参数有cookie值表示为language 然后进行一个判断&#xff0c;如果参数不是等于英语&#xff0c;就加上.php&#xff0c;那我们就可以在前面进行注入一个参数&#xff0c;即flag&#xff0c; payload&#xff1a;COOKIE:languageflag …

手撕LFU

博主介绍&#xff1a;程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章&#xff0c;首发gzh&#xff0c;见文末&#x1f447;&#x1f…

火影bug,未保证短时间数据一致性,拿这个例子讲一下Redis

本文只拿这个游戏的bug来举例Redis&#xff0c;如果有不妥的地方&#xff0c;联系我进行删除 描述&#xff1a;今天在高速上打火影&#xff08;有隧道&#xff0c;有时候会卡&#xff09;&#xff0c;发现了个bug&#xff0c;我点了两次-1000的忍玉&#xff08;大概用了1千七百…

KRaft (Kafka 4.0) 集群配置指南(超简单,脱离 ZooKeeper 集群)还包含了简化测试指令的脚本!!!

docker-compose方式部署kafka集群 Kafka 4.0 引入了 KRaft 模式&#xff08;Kafka Raft Metadata Mode&#xff09;&#xff0c;它使 Kafka 集群不再依赖 ZooKeeper 进行元数据管理。KRaft 模式简化了 Kafka 部署和管理&#xff0c;不需要额外配置 ZooKeeper 服务&#xff0c;…

Admyral - 可扩展的GRC工程自动化平台

文章目录 一、关于 Admyral相关链接资源关键特性 二、安装系统要求 三、快速开始1、启动服务 四、核心功能1、自动化即代码2、AI增强工作流3、双向同步编辑器4、工作流监控5、企业级基础设施 五、示例应用六、其他信息许可证遥测说明 一、关于 Admyral Admyral 是一个基于 Pyt…

DDR在PCB布局布线时的注意事项及设计要点

一、布局注意事项 控制器与DDR颗粒的布局 靠近原则&#xff1a;控制器与DDR颗粒应尽量靠近&#xff0c;缩短时钟&#xff08;CLK&#xff09;、地址/控制线&#xff08;CA&#xff09;、数据线&#xff08;DQ/DQS&#xff09;的走线长度&#xff0c;减少信号延迟差异。 分组隔…

计算机网络-LDP工作过程详解

前面我们已经学习了LDP的基础概念&#xff0c;了解了LDP会话的建立、LDP的标签控制等知识&#xff0c;今天来整体过一遍LDP的一个工作过程&#xff0c;后面我们再通过实验深入学习。 一、LDP标签分发 标签分发需要基于基础的路由协议建立LDP会话&#xff0c;激活MPLS和LDP。以…

解构与重构:自动化测试框架的进阶认知之旅

目录 一、自动化测试的介绍 &#xff08;一&#xff09;自动化测试的起源与发展 &#xff08;二&#xff09;自动化测试的定义与目标 &#xff08;三&#xff09;自动化测试的适用场景 二、什么是自动化测试框架 &#xff08;一&#xff09;自动化测试框架的定义 &#x…

跑不出的循环 | LoveySelf 系列定位

最近开始陷入一轮一轮的循环状态&#xff0c;无奈&#xff0c;只能自我整理一下。23年暑假&#xff0c;在计算机系折腾了一年后&#xff0c;重新打开博客&#xff0c;回想在数学系摸索博客写作的日子&#xff0c;思绪涌上心头&#xff0c;我们决定拾起这份力量。当时觉得 hexo …

Redis最新入门教程

文章目录 Redis最新入门教程1.安装Redis2.连接Redis3.Redis环境变量配置4.入门Redis4.1 Redis的数据结构4.2 Redis的Key4.3 Redis-String4.4 Redis-Hash4.5 Redis-List4.6 Redis-Set4.7 Redis-Zset 5.在Java中使用Redis6.缓存雪崩、击穿、穿透6.1 缓存雪崩6.2 缓冲击穿6.3 缓冲…

一文读懂Python之requests模块(36)

一、requests模块简介 requests模块是python中原生的一款基于网络请求的模块&#xff0c;功能强大&#xff0c;简单便捷且高效 &#xff0c;该模块可以模拟浏览器发送请求&#xff0c;主要包括指定url、发起请求、获取响应数据和持久化存储&#xff0c;包括 GET、POST、PUT、…