Files
nanocode/wanandroid/uniapp_android/index.html
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

808 lines
38 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>玩Android - 首页</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Roboto', 'Noto Sans SC', sans-serif; background: #F5F5F5; }
/* 容器 */
.container { max-width: 750px; margin: 0 auto; background: white; min-height: 100vh; }
/* 状态栏 */
.status-bar { height: 40px; background: #6200EE; }
/* 顶部导航 */
.top-nav { background: #6200EE; padding: 12px 16px; display: flex; align-items: center; justify-content: space-between; color: white; }
.nav-title { font-size: 20px; font-weight: 500; }
.nav-actions { display: flex; gap: 16px; }
.nav-icon { font-size: 24px; cursor: pointer; }
/* 搜索栏 */
.search-bar { background: #6200EE; padding: 12px 16px; }
.search-container { background: rgba(255,255,255,0.9); border-radius: 24px; padding: 12px 16px; display: flex; align-items: center; }
.search-icon { font-size: 20px; margin-right: 12px; color: #6200EE; }
.search-input { font-size: 16px; color: #212121; flex: 1; border: none; outline: none; background: transparent; }
.search-input::placeholder { color: #757575; }
/* Banner轮播图 */
.banner-container { padding: 16px; position: relative; }
.banner-slider { position: relative; height: 160px; border-radius: 16px; overflow: hidden; }
.banner-item { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 0.5s; display: flex; flex-direction: column; justify-content: center; align-items: center; color: white; padding: 20px; text-align: center; }
.banner-item.active { opacity: 1; }
.banner-item:nth-child(1) { background: linear-gradient(135deg, #6200EE, #3700B3); }
.banner-item:nth-child(2) { background: linear-gradient(135deg, #03DAC6, #018786); }
.banner-item:nth-child(3) { background: linear-gradient(135deg, #FF5252, #B00020); }
.banner-title { font-size: 20px; font-weight: 500; margin-bottom: 8px; }
.banner-desc { font-size: 14px; opacity: 0.9; margin-bottom: 12px; }
.banner-link { background: rgba(255,255,255,0.2); padding: 6px 16px; border-radius: 20px; font-size: 14px; cursor: pointer; }
.banner-dots { display: flex; justify-content: center; margin-top: 12px; gap: 8px; }
.banner-dot { width: 8px; height: 8px; border-radius: 50%; background: #E0E0E0; cursor: pointer; }
.banner-dot.active { background: #6200EE; }
/* 文章列表 */
.articles-container { padding: 0 16px 80px; }
.section-title { font-size: 18px; font-weight: 500; margin: 24px 0 16px; color: #212121; display: flex; align-items: center; }
.section-title::before { content: "📰"; margin-right: 8px; }
/* 文章卡片 */
.article-card { background: white; border-radius: 16px; padding: 20px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); transition: all 0.3s; cursor: pointer; }
.article-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.12); transform: translateY(-2px); }
.article-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
.article-title { font-size: 18px; font-weight: 500; color: #212121; line-height: 1.4; flex: 1; }
.article-fresh { background: #FF5252; color: white; font-size: 12px; padding: 2px 8px; border-radius: 10px; margin-left: 8px; }
.article-meta { display: flex; align-items: center; margin-bottom: 12px; font-size: 14px; color: #757575; }
.article-author { margin-right: 16px; }
.article-time { margin-right: 16px; }
.article-category { background: #E0E0E0; padding: 2px 8px; border-radius: 10px; font-size: 12px; }
.article-content { font-size: 15px; color: #616161; line-height: 1.6; margin-bottom: 16px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.article-footer { display: flex; justify-content: space-between; align-items: center; }
.article-stats { display: flex; gap: 16px; }
.stat-item { display: flex; align-items: center; font-size: 14px; color: #757575; }
.stat-icon { margin-right: 4px; }
.article-actions { display: flex; gap: 12px; }
.action-btn { background: #F5F5F5; border: none; padding: 6px 12px; border-radius: 16px; font-size: 14px; color: #6200EE; cursor: pointer; transition: all 0.3s; }
.action-btn:hover { background: #6200EE; color: white; }
/* 底部导航 */
.tab-bar { position: fixed; bottom: 0; left: 0; right: 0; background: white; border-top: 1px solid #EEEEEE; display: flex; justify-content: space-around; padding: 12px 0; max-width: 750px; margin: 0 auto; z-index: 100; }
.tab-item { display: flex; flex-direction: column; align-items: center; padding: 8px 16px; border-radius: 12px; transition: all 0.3s; cursor: pointer; }
.tab-item.active { background: rgba(98, 0, 238, 0.08); }
.tab-icon { font-size: 24px; margin-bottom: 4px; }
.tab-text { font-size: 12px; }
.tab-item.active .tab-icon, .tab-item.active .tab-text { color: #6200EE; }
.tab-item:not(.active) .tab-icon, .tab-item:not(.active) .tab-text { color: #757575; }
/* 文章详情页 */
.article-detail { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: white; z-index: 1000; overflow-y: auto; }
.detail-header { background: #6200EE; padding: 16px; display: flex; align-items: center; justify-content: space-between; color: white; }
.detail-back { font-size: 24px; cursor: pointer; }
.detail-title { font-size: 18px; font-weight: 500; }
.detail-content { padding: 24px; }
.detail-title-main { font-size: 24px; font-weight: 500; margin-bottom: 16px; color: #212121; }
.detail-meta { display: flex; align-items: center; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 1px solid #EEEEEE; }
.detail-author { margin-right: 16px; font-size: 16px; color: #6200EE; }
.detail-time { font-size: 14px; color: #757575; }
.detail-body { font-size: 16px; line-height: 1.8; color: #424242; }
.detail-body p { margin-bottom: 16px; }
.detail-body h2 { font-size: 20px; font-weight: 500; margin: 24px 0 16px; color: #212121; }
.detail-body h3 { font-size: 18px; font-weight: 500; margin: 20px 0 12px; color: #212121; }
.detail-body code { background: #F5F5F5; padding: 2px 6px; border-radius: 4px; font-family: 'Courier New', monospace; }
.detail-body pre { background: #F5F5F5; padding: 16px; border-radius: 8px; overflow-x: auto; margin: 16px 0; }
.detail-footer { padding: 24px; border-top: 1px solid #EEEEEE; margin-top: 32px; }
.detail-actions { display: flex; justify-content: space-between; }
/* 加载更多 */
.load-more { text-align: center; padding: 24px; }
.load-btn { background: #6200EE; color: white; border: none; padding: 12px 32px; border-radius: 24px; font-size: 16px; cursor: pointer; transition: all 0.3s; }
.load-btn:hover { background: #3700B3; }
/* 安全区域 */
.safe-area { height: 80px; }
/* 加载动画 */
.loading { text-align: center; padding: 40px; color: #757575; }
.loading-spinner { width: 40px; height: 40px; border: 4px solid #E0E0E0; border-top: 4px solid #6200EE; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 16px; }
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
@media (max-width: 600px) {
.article-header { flex-direction: column; }
.article-title { margin-bottom: 8px; }
.article-footer { flex-direction: column; align-items: flex-start; gap: 12px; }
.article-actions { align-self: flex-end; }
}
</style>
</head>
<body>
<!-- 文章列表页面 -->
<div class="container" id="listPage">
<!-- 状态栏 -->
<div class="status-bar"></div>
<!-- 顶部导航 -->
<div class="top-nav">
<div class="nav-title">玩Android</div>
<div class="nav-actions">
<div class="nav-icon" onclick="showMenu()">⋮</div>
</div>
</div>
<!-- 搜索栏 -->
<div class="search-bar">
<div class="search-container">
<div class="search-icon">🔍</div>
<input type="text" class="search-input" placeholder="搜索wanandroid.com的内容..." id="searchInput" onkeypress="handleSearchKeypress(event)">
</div>
</div>
<!-- Banner轮播图 -->
<div class="banner-container">
<div class="banner-slider" id="bannerSlider">
<!-- Banner内容会通过JavaScript动态生成 -->
</div>
<div class="banner-dots" id="bannerDots">
<!-- Banner指示点会通过JavaScript动态生成 -->
</div>
</div>
<!-- 文章列表 -->
<div class="articles-container">
<div class="section-title">最新文章</div>
<!-- 文章列表容器 -->
<div id="articlesList">
<div class="loading" id="loadingArticles">
<div class="loading-spinner"></div>
<div>正在加载文章...</div>
</div>
</div>
<!-- 加载更多 -->
<div class="load-more" id="loadMoreContainer" style="display: none;">
<button class="load-btn" onclick="loadMoreArticles()">加载更多</button>
</div>
</div>
<!-- 安全区域 -->
<div class="safe-area"></div>
<!-- 底部导航 -->
<div class="tab-bar">
<div class="tab-item active" onclick="switchTab('home', event)">
<div class="tab-icon">🏠</div>
<div class="tab-text">首页</div>
</div>
<div class="tab-item" onclick="switchTab('project', event)">
<div class="tab-icon">📦</div>
<div class="tab-text">项目</div>
</div>
<div class="tab-item" onclick="switchTab('wechat', event)">
<div class="tab-icon">📱</div>
<div class="tab-text">公众号</div>
</div>
<div class="tab-item" onclick="switchTab('system', event)">
<div class="tab-icon">🌳</div>
<div class="tab-text">体系</div>
</div>
<div class="tab-item" onclick="switchTab('profile', event)">
<div class="tab-icon">👤</div>
<div class="tab-text">我的</div>
</div>
</div>
</div>
<!-- 文章详情页 -->
<div class="article-detail" id="detailPage">
<div class="detail-header">
<div class="detail-back" onclick="closeDetail()">←</div>
<div class="detail-title">文章详情</div>
<div style="width: 24px;"></div>
</div>
<div class="detail-content">
<div id="detailContent">
<div class="loading" id="loadingDetail">
<div class="loading-spinner"></div>
<div>正在加载文章详情...</div>
</div>
</div>
</div>
</div>
<script>
// 当前页码
let currentPage = 0;
let isLoading = false;
let hasMore = true;
// 存储已加载的文章列表(用于详情展示)
let loadedArticles = [];
// 初始化页面
document.addEventListener('DOMContentLoaded', function() {
console.log('玩Android首页已加载');
console.log('公网访问: http://129.211.173.87:3000/index_fixed.html');
// 加载Banner数据
loadBanners();
// 加载文章列表
loadArticles();
});
// 加载Banner数据
async function loadBanners() {
try {
const response = await fetch('/api/banner/json');
const data = await response.json();
if (data.errorCode === 0 && data.data && data.data.length > 0) {
renderBanners(data.data);
} else {
// 使用默认Banner数据
renderDefaultBanners();
}
} catch (error) {
console.error('加载Banner失败:', error);
renderDefaultBanners();
}
}
// 渲染Banner
function renderBanners(banners) {
const slider = document.getElementById('bannerSlider');
const dots = document.getElementById('bannerDots');
slider.innerHTML = '';
dots.innerHTML = '';
banners.forEach((banner, index) => {
// Banner项
const bannerItem = document.createElement('div');
bannerItem.className = `banner-item ${index === 0 ? 'active' : ''}`;
bannerItem.innerHTML = `
<div class="banner-title">${banner.title || '玩Android'}</div>
<div class="banner-desc">${banner.desc || 'Android学习平台'}</div>
<div class="banner-link" onclick="openBannerLink('${banner.url || '#'}')">查看详情</div>
`;
slider.appendChild(bannerItem);
// Banner指示点
const dot = document.createElement('div');
dot.className = `banner-dot ${index === 0 ? 'active' : ''}`;
dot.onclick = () => switchBanner(index);
dots.appendChild(dot);
});
// 自动轮播
startBannerAutoPlay();
}
// 渲染默认Banner
function renderDefaultBanners() {
const defaultBanners = [
{
title: '玩Android',
desc: 'Android学习平台',
url: 'https://www.wanandroid.com'
},
{
title: 'Material Design 3',
desc: '最新设计规范',
url: 'https://m3.material.io'
},
{
title: 'Uniapp开发',
desc: '跨平台应用开发',
url: 'https://uniapp.dcloud.net.cn'
}
];
renderBanners(defaultBanners);
}
// 切换Banner
let currentBannerIndex = 0;
let bannerInterval;
function switchBanner(index) {
const banners = document.querySelectorAll('.banner-item');
const dots = document.querySelectorAll('.banner-dot');
banners[currentBannerIndex].classList.remove('active');
dots[currentBannerIndex].classList.remove('active');
currentBannerIndex = index;
banners[currentBannerIndex].classList.add('active');
dots[currentBannerIndex].classList.add('active');
}
// 开始自动轮播
function startBannerAutoPlay() {
if (bannerInterval) clearInterval(bannerInterval);
bannerInterval = setInterval(() => {
const banners = document.querySelectorAll('.banner-item');
const nextIndex = (currentBannerIndex + 1) % banners.length;
switchBanner(nextIndex);
}, 3000);
}
// 打开Banner链接
function openBannerLink(url) {
if (url && url !== '#') {
window.open(url, '_blank');
}
}
// 加载文章列表
async function loadArticles() {
if (isLoading || !hasMore) return;
isLoading = true;
try {
const response = await fetch(`/api/article/list/${currentPage}/json`);
const data = await response.json();
if (data.errorCode === 0 && data.data && data.data.datas) {
renderArticles(data.data.datas);
hasMore = !data.data.over;
// 显示或隐藏加载更多按钮
const loadMoreContainer = document.getElementById('loadMoreContainer');
loadMoreContainer.style.display = hasMore ? 'block' : 'none';
} else {
// 使用默认文章数据
renderDefaultArticles();
// 默认显示加载更多按钮(最多3页)
hasMore = currentPage < 3;
const loadMoreContainer = document.getElementById('loadMoreContainer');
loadMoreContainer.style.display = hasMore ? 'block' : 'none';
}
} catch (error) {
console.error('加载文章失败:', error);
renderDefaultArticles();
// 默认显示加载更多按钮(最多3页)
hasMore = currentPage < 3;
const loadMoreContainer = document.getElementById('loadMoreContainer');
loadMoreContainer.style.display = hasMore ? 'block' : 'none';
} finally {
isLoading = false;
document.getElementById('loadingArticles').style.display = 'none';
}
}
// 渲染文章列表
function renderArticles(articles) {
const container = document.getElementById('articlesList');
// 如果是第一页,清空容器和文章列表
if (currentPage === 0) {
container.innerHTML = '';
loadedArticles = [];
}
// 保存文章到全局列表
loadedArticles.push(...articles);
articles.forEach(article => {
const articleElement = document.createElement('div');
articleElement.className = 'article-card';
articleElement.setAttribute('data-id', article.id);
articleElement.onclick = () => showArticleDetail(article.id);
// 格式化时间
const publishTime = new Date(article.publishTime);
const timeAgo = getTimeAgo(publishTime);
articleElement.innerHTML = `
<div class="article-header">
<div class="article-title">${article.title || '无标题'}</div>
${article.fresh ? '<div class="article-fresh">新</div>' : ''}
</div>
<div class="article-meta">
<div class="article-author">👤 ${article.author || '未知作者'}</div>
<div class="article-time">🕒 ${timeAgo}</div>
${article.superChapterName ? `<div class="article-category">${article.superChapterName}</div>` : ''}
</div>
<div class="article-content">${article.desc || '暂无描述'}</div>
<div class="article-footer">
<div class="article-stats">
<div class="stat-item">
<span class="stat-icon">👍</span>
<span>${article.zan || 0}</span>
</div>
<div class="stat-item">
<span class="stat-icon">💬</span>
<span>${article.comments || 0}</span>
</div>
<div class="stat-item">
<span class="stat-icon">⭐</span>
<span>${article.collect ? '已收藏' : '未收藏'}</span>
</div>
</div>
<div class="article-actions">
<button class="action-btn" onclick="event.stopPropagation(); likeArticle(${article.id})">点赞</button>
<button class="action-btn" onclick="event.stopPropagation(); collectArticle(${article.id})">${article.collect ? '取消收藏' : '收藏'}</button>
</div>
</div>
`;
container.appendChild(articleElement);
});
}
// 渲染默认文章 - 根据页码生成不同内容
function renderDefaultArticles() {
// 基础文章列表
const baseArticles = [
{
id: 2335,
title: "玩Android API接口完整文档",
author: "鸿洋",
publishTime: Date.now() - 18000000,
superChapterName: "API文档",
desc: "玩Android网站提供的完整API接口文档,包含用户模块、文章模块、知识体系、导航数据等所有接口的详细说明。",
zan: 128,
collect: false,
comments: 45,
fresh: true,
link: "https://www.wanandroid.com/blog/show/2"
},
{
id: 2336,
title: "Android开发教程合集",
author: "玩Android",
publishTime: Date.now() - 21600000,
superChapterName: "教程",
desc: "精选Android开发教程,涵盖基础入门、进阶提升、性能优化、架构设计等多个方面。",
zan: 96,
collect: true,
comments: 32,
fresh: false,
link: "https://www.wanandroid.com/"
},
{
id: 1,
title: "玩Android Material Design客户端发布",
author: "Material Design",
publishTime: Date.now() - 3600000,
superChapterName: "前端开发",
desc: "玩Android Material Design客户端正式发布!这是一个基于Uniapp框架开发的Android应用,完全遵循Material Design 3设计规范。",
zan: 42,
collect: false,
comments: 12,
fresh: true
},
{
id: 2,
title: "Uniapp框架Material Design实践指南",
author: "Uniapp团队",
publishTime: Date.now() - 7200000,
superChapterName: "Uniapp",
desc: "本文详细介绍了如何在Uniapp框架中实现Material Design设计规范。从颜色系统、排版、图标到组件实现,提供了完整的实践指南和代码示例。",
zan: 28,
collect: true,
comments: 8,
fresh: false
},
{
id: 3,
title: "Android Material Design 3新特性详解",
author: "Google",
publishTime: Date.now() - 10800000,
superChapterName: "Android",
desc: "Material Design 3带来了动态颜色、设计令牌、组件更新等新特性。本文详细解析了这些新特性,并提供了在Android应用中的实现方法。",
zan: 56,
collect: false,
comments: 24,
fresh: false
}
];
// 根据页码生成额外文章
const extraArticles = [];
const categories = ["Kotlin", "Jetpack", "Compose", "架构", "性能", "安全", "测试", "工具"];
const authors = ["Android团队", "Kotlin专家", "架构师", "开发者", "技术博主", "Google开发者", "开源社区"];
// 生成当前页的额外文章
for (let i = 0; i < 5; i++) {
const articleNum = currentPage * 5 + i + 10;
const category = categories[(currentPage + i) % categories.length];
extraArticles.push({
id: 100 + articleNum,
title: `${category}开发实战教程 - 第${currentPage + 1}期`,
author: authors[(currentPage + i) % authors.length],
publishTime: Date.now() - (articleNum * 3600000),
superChapterName: category,
desc: `本教程深入讲解${category}的核心概念和实战技巧,帮助开发者快速掌握${category}开发。包含代码示例和最佳实践。`,
zan: 20 + (articleNum % 50),
collect: articleNum % 2 === 0,
comments: 5 + (articleNum % 20),
fresh: articleNum < 15
});
}
// 第一页显示基础文章,后续页显示生成的文章
let displayArticles;
if (currentPage === 0) {
displayArticles = [...baseArticles, ...extraArticles];
} else {
displayArticles = extraArticles;
}
// 保存到全局列表
if (currentPage === 0) {
loadedArticles = [...displayArticles];
} else {
loadedArticles.push(...displayArticles);
}
renderArticles(displayArticles);
}
// 加载更多文章
function loadMoreArticles() {
currentPage++;
loadArticles();
}
// 显示文章详情
async function showArticleDetail(articleId) {
document.getElementById('listPage').style.display = 'none';
document.getElementById('detailPage').style.display = 'block';
const detailContent = document.getElementById('detailContent');
detailContent.innerHTML = `
<div class="loading" id="loadingDetail">
<div class="loading-spinner"></div>
<div>正在加载文章详情...</div>
</div>
`;
try {
// 这里应该调用文章详情API,但为了简化,我们使用模拟数据
await new Promise(resolve => setTimeout(resolve, 500));
// 模拟文章详情数据
const articleDetails = {
1: {
title: "玩Android Material Design客户端发布",
author: "Material Design",
publishTime: Date.now() - 3600000,
content: `
<h1>玩Android Material Design客户端发布</h1>
<p>玩Android Material Design客户端正式发布!这是一个基于Uniapp框架开发的Android应用,完全遵循Material Design 3设计规范。</p>
<h2>主要特性</h2>
<p>1. <strong>Material Design 3规范</strong>:完全遵循Google最新的Material Design 3设计语言</p>
<p>2. <strong>紫色主色系统</strong>:采用#6200EE作为主色,搭配#03DAC6作为强调色</p>
<p>3. <strong>完整组件库</strong>:提供卡片、按钮、导航栏、对话框等完整组件</p>
<p>4. <strong>响应式设计</strong>:完美适配手机、平板和桌面设备</p>
<h2>技术栈</h2>
<ul>
<li>前端框架:Uniapp + Vue 3</li>
<li>UI组件:自定义Material Design组件</li>
<li>状态管理:Pinia</li>
<li>网络请求:Axios + 拦截器</li>
<li>构建工具:Vite</li>
</ul>
`
},
2: {
title: "Uniapp框架Material Design实践指南",
author: "Uniapp团队",
publishTime: Date.now() - 7200000,
content: `
<h1>Uniapp框架Material Design实践指南</h1>
<p>Material Design是Google推出的设计语言,强调材质、动效和层次感。在Uniapp中实现Material Design需要关注以下几个方面:</p>
<h2>1. 颜色系统</h2>
<p>Material Design 3引入了动态颜色系统,可以根据壁纸自动生成调色板。在Uniapp中可以通过CSS变量实现:</p>
<pre><code>:root {
--md-primary: #6200EE;
--md-secondary: #03DAC6;
--md-surface: #FFFFFF;
--md-background: #F5F5F5;
--md-on-primary: #FFFFFF;
--md-on-secondary: #000000;
}</code></pre>
`
},
3: {
title: "Android Material Design 3新特性详解",
author: "Google",
publishTime: Date.now() - 10800000,
content: `
<h1>Android Material Design 3新特性详解</h1>
<p>Material Design 3是Google设计语言的最新版本,带来了许多重要的更新和改进。</p>
<h2>1. 动态颜色(Dynamic Color)</h2>
<p>动态颜色是Material Design 3的核心特性,可以根据用户的壁纸自动生成调色板:</p>
<pre><code>// Kotlin实现
val dynamicColor = DynamicColors.wrapContextIfAvailable(context)
setContentView(dynamicColor)</code></pre>
`
}
};
// 从预定义详情中获取,如果没有则从loadedArticles列表中查找
let article = articleDetails[articleId];
// 如果预定义详情中没有,从loadedArticles中查找
if (!article) {
const foundArticle = loadedArticles.find(a => a.id == articleId);
if (foundArticle) {
// 如果有link字段,显示外部链接提示
const externalLinkHtml = foundArticle.link ? `
<div style="background: #E3F2FD; padding: 16px; border-radius: 8px; margin: 20px 0;">
<p style="margin: 0 0 12px 0; color: #1565C0;">📎 该文章来自外部链接</p>
<a href="${foundArticle.link}" target="_blank" style="display: inline-block; background: #6200EE; color: white; padding: 10px 20px; border-radius: 20px; text-decoration: none;">查看原文</a>
</div>
` : '';
article = {
title: foundArticle.title,
author: foundArticle.author || '未知作者',
publishTime: foundArticle.publishTime,
content: `
<h1>${foundArticle.title}</h1>
<p>${foundArticle.desc || '暂无描述'}</p>
${externalLinkHtml}
<hr style="margin: 24px 0; border: none; border-top: 1px solid #E0E0E0;">
<p style="color: #757575; font-size: 14px;">💡 提示:完整文章内容需要访问原文查看</p>
`
};
} else {
// 如果都找不到,显示错误信息
article = {
title: "文章详情",
author: "未知作者",
publishTime: Date.now(),
content: "<p>文章内容加载失败,请稍后再试</p>"
};
}
}
const timeAgo = getTimeAgo(new Date(article.publishTime));
detailContent.innerHTML = `
<div class="detail-title-main">${article.title}</div>
<div class="detail-meta">
<div class="detail-author">👤 ${article.author}</div>
<div class="detail-time">🕒 ${timeAgo}</div>
</div>
<div class="detail-body">${article.content}</div>
<div class="detail-footer">
<div class="detail-actions">
<button class="action-btn" onclick="likeArticle(${articleId})">👍 点赞</button>
<button class="action-btn" onclick="collectArticle(${articleId})">⭐ 收藏</button>
<button class="action-btn" onclick="shareArticle(${articleId})">📤 分享</button>
</div>
</div>
`;
} catch (error) {
console.error('加载文章详情失败:', error);
detailContent.innerHTML = `
<div class="detail-title-main">加载失败</div>
<div class="detail-body">
<p>抱歉,加载文章详情时出现错误。</p>
<button class="action-btn" onclick="closeDetail()">返回</button>
</div>
`;
}
}
// 关闭文章详情
function closeDetail() {
document.getElementById('listPage').style.display = 'block';
document.getElementById('detailPage').style.display = 'none';
}
// 处理搜索按键
function handleSearchKeypress(event) {
if (event.key === 'Enter') {
const query = document.getElementById('searchInput').value.trim();
if (query) {
alert(`搜索: ${query}\n\n搜索功能开发中,将搜索wanandroid.com的内容`);
// 这里应该调用搜索API
}
}
}
// 点赞文章
function likeArticle(articleId) {
alert(`已点赞文章 ${articleId}!`);
}
// 收藏文章
function collectArticle(articleId) {
alert(`已收藏文章 ${articleId}!`);
}
// 分享文章
function shareArticle(articleId) {
alert(`分享文章 ${articleId}!`);
}
// 显示菜单
function showMenu() {
alert('菜单功能开发中...\n\n包括设置、关于、反馈等功能');
}
// 切换Tab - 修复版:已完成的页面直接跳转,未完成的显示提示
// 版本: 2026-03-18-v2 (修复体系Tab跳转问题)
function switchTab(tab, event) {
console.log('switchTab called with:', tab);
console.log('event:', event);
// 更新选中状态
document.querySelectorAll('.tab-item').forEach(item => {
item.classList.remove('active');
});
// 确保event存在
if (event && event.target) {
const tabItem = event.target.closest('.tab-item');
if (tabItem) {
tabItem.classList.add('active');
}
}
// 根据tab进行跳转或提示
switch(tab) {
case 'home':
console.log('首页Tab - 当前页面');
// 首页已开发完成,当前页面
// 不需要跳转
break;
case 'project':
console.log('项目Tab - 跳转到项目页面');
// 项目页面已开发完成,直接跳转
window.location.href = '/projects_fixed.html';
break;
case 'wechat':
console.log('公众号Tab - 显示开发中提示');
// 公众号页面未开发
window.location.href = '/wechat.html';
break;
case 'system':
console.log('体系Tab - 跳转到体系页面');
console.log('跳转URL:', '/tree.html');
// 体系页面已开发完成,直接跳转
window.location.href = '/tree.html';
break;
case 'profile':
console.log('我的Tab - 跳转到我的页面');
// 我的页面已开发完成,直接跳转
window.location.href = '/profile.html';
break;
default:
console.log('未知Tab:', tab);
}
}
// 获取相对时间
function getTimeAgo(date) {
const now = new Date();
const diff = now - date;
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 1) return '刚刚';
if (minutes < 60) return `${minutes}分钟前`;
if (hours < 24) return `${hours}小时前`;
if (days < 30) return `${days}天前`;
return date.toLocaleDateString();
}
</script>
</body>
</html>