四、JavaScript实现
4.1 主题切换功能
功能描述
博客实现了亮色/暗色主题切换功能,核心实现包括:🌓
使用CSS变量定义不同主题的颜色方案
通过在body上切换CSS类(light-mode/dark-mode)实现主题转换
使用localStorage存储用户主题偏好
根据当前时间自动选择默认主题(白天/黑夜)
Feature Description
The blog implements light/dark theme switching functionality, with core implementations including:🌓
Using CSS variables to define color schemes for different themes
Implementing theme conversion by switching CSS classes (light-mode/dark-mode) on the body
Using localStorage to store user theme preferences
Automatically selecting the default theme based on current time (day/night)
核心代码
主题切换功能的JavaScript实现:
Core Code
JavaScript implementation of theme switching functionality:
// 根据当前时间获取合适的主题
function getThemeByTime() {
const hour = new Date().getHours();
// 6:00-18:00 为日间模式,19:00-5:00 为夜间模式
return (hour >= 6 && hour <= 18) ? 'light-mode' : 'dark-mode';
}
// 检查用户之前的主题偏好
function checkThemePreference() {
const savedTheme = localStorage.getItem('theme');
// 如果用户手动设置了主题,优先使用
if (savedTheme) {
document.body.className = savedTheme;
updateThemeToggleIcon(savedTheme);
}
// 如果没有手动设置,根据时间自动判断
else {
const timeBasedTheme = getThemeByTime();
document.body.className = timeBasedTheme;
updateThemeToggleIcon(timeBasedTheme);
}
}
// 切换主题
function toggleTheme() {
if (document.body.classList.contains('dark-mode')) {
document.body.classList.remove('dark-mode');
document.body.classList.add('light-mode');
localStorage.setItem('theme', 'light-mode');
updateThemeToggleIcon('light-mode');
} else {
document.body.classList.remove('light-mode');
document.body.classList.add('dark-mode');
localStorage.setItem('theme', 'dark-mode');
updateThemeToggleIcon('dark-mode');
}
}
4.2 语言切换功能
多语言实现
博客的多语言实现原理:🔄
通过在body上切换CSS类(en/zh)控制当前语言
使用数据属性存储双语文本
针对更长的内容,使用带有显示/隐藏控制的容器元素
使用localStorage保存用户语言偏好
Multilingual Implementation
Implementation principles of the blog's multilingual functionality:🔄
Controlling the current language by switching CSS classes (en/zh) on the body
Using data attributes to store bilingual text
For longer content, using container elements with display/hide controls
Using localStorage to save user language preferences
核心实现
语言切换的JavaScript函数:
Core Implementation
JavaScript function for language switching:
// 更新所有带有语言属性的元素
function updateAllLanguageElements(lang) {
const elements = document.querySelectorAll('[data-en][data-zh]');
elements.forEach(element => {
element.textContent = element.getAttribute(`data-${lang}`);
});
// 更新搜索框占位符
const searchInputs = document.querySelectorAll('input[data-en-placeholder][data-zh-placeholder]');
searchInputs.forEach(input => {
input.placeholder = input.getAttribute(`data-${lang}-placeholder`);
});
// 更新长文本内容的显示/隐藏
const zhContents = document.querySelectorAll('.zh-content');
const enContents = document.querySelectorAll('.en-content');
if (lang === 'zh') {
zhContents.forEach(el => el.style.display = 'block');
enContents.forEach(el => el.style.display = 'none');
} else {
zhContents.forEach(el => el.style.display = 'none');
enContents.forEach(el => el.style.display = 'block');
}
}
4.3 动态内容加载
动态加载优势
博客列表页使用JavaScript动态加载文章内容,这种方式相比于静态HTML有以下优势:🔄
更容易实现文章过滤、搜索和分页功能
便于将来扩展,比如从API或JSON文件加载内容
避免重复的HTML代码,提高维护效率
Dynamic Loading Advantages
The blog list page uses JavaScript to dynamically load article content,
which has the following advantages compared to static HTML:🔄
Easier implementation of article filtering, search, and pagination
Convenient for future expansion, such as loading content from API or JSON files
Avoids repetitive HTML code, improving maintenance efficiency
实现示例
博客文章数据和加载函数:
Implementation Example
Blog post data and loading function:
// 博客文章数据示例
const blogPosts = [
{
id: 1,
title: { zh: "从零构建个人博客:技术栈与架构详解", en: "Building a Personal Blog from Scratch: Tech Stack and Architecture" },
excerpt: { zh: "详细介绍个人博客的技术栈、架构设计和核心功能实现...", en: "Detailed introduction to the tech stack, architecture design, and core functionality implementation of a personal blog..." },
date: "2025-04-25",
category: "tech",
tags: ["web-development", "frontend", "html-css-js"],
url: "blog/tech/blog-building.html"
},
// 更多文章...
];
// 加载特定页面的文章
function loadPagePosts(page, filter = 'all') {
const postsPerPage = 6;
const startIndex = (page - 1) * postsPerPage;
const endIndex = startIndex + postsPerPage;
// 根据筛选条件过滤文章
let filteredPosts = blogPosts;
if (filter !== 'all') {
filteredPosts = blogPosts.filter(post => post.tags.includes(filter) || post.category === filter);
}
const currentPosts = filteredPosts.slice(startIndex, endIndex);
const blogList = document.querySelector('.blog-list');
blogList.innerHTML = '';
// 当前语言
const currentLang = document.body.classList.contains('en') ? 'en' : 'zh';
// 生成文章卡片HTML
currentPosts.forEach(post => {
const postElement = document.createElement('article');
postElement.className = 'blog-post';
postElement.innerHTML = `
${post.date}
${post.title[currentLang]}
${post.excerpt[currentLang]}
${currentLang === 'en' ? 'Read More' : '阅读更多'}
`;
blogList.appendChild(postElement);
});
// 更新分页状态
updatePagination(page, Math.ceil(filteredPosts.length / postsPerPage));
}
4.4 性能优化技巧
优化策略
在JavaScript实现中采用了多种性能优化措施:⚡
事件委托 - 减少事件监听器数量,提高性能
防抖与节流 - 优化频繁触发的事件处理(如搜索、滚动)
异步加载 - 非关键资源延迟加载
代码模块化 - 按需加载不同功能模块
缓存DOM查询 - 避免重复查询DOM元素
Optimization Strategies
Various performance optimization measures were adopted
in the JavaScript implementation:⚡
Event Delegation - Reducing the number of event listeners for better performance
Debouncing and Throttling - Optimizing frequently triggered event handlers (e.g., search, scroll)
Asynchronous Loading - Delayed loading of non-critical resources
Code Modularization - Loading different functional modules as needed
Caching DOM Queries - Avoiding repeated querying of DOM elements
防抖示例
防抖函数和搜索优化实现:
Debounce Example
Debounce function and search optimization implementation:
// 防抖函数实现
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 博客搜索实现(带防抖)
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.querySelector('.blog-search input');
// 使用防抖优化搜索,避免每输入一个字符就触发搜索
const debouncedSearch = debounce(function() {
const searchTerm = this.value.toLowerCase().trim();
performSearch(searchTerm);
}, 300);
if (searchInput) {
searchInput.addEventListener('input', debouncedSearch);
}
});