a
This commit is contained in:
@@ -0,0 +1,678 @@
|
||||
<!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')">
|
||||
<div class="tab-icon">🏠</div>
|
||||
<div class="tab-text">首页</div>
|
||||
</div>
|
||||
<div class="tab-item" onclick="switchTab('project')">
|
||||
<div class="tab-icon">📦</div>
|
||||
<div class="tab-text">项目</div>
|
||||
</div>
|
||||
<div class="tab-item" onclick="switchTab('wechat')">
|
||||
<div class="tab-icon">📱</div>
|
||||
<div class="tab-text">公众号</div>
|
||||
</div>
|
||||
<div class="tab-item" onclick="switchTab('system')">
|
||||
<div class="tab-icon">🌳</div>
|
||||
<div class="tab-text">体系</div>
|
||||
</div>
|
||||
<div class="tab-item" onclick="switchTab('profile')">
|
||||
<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;
|
||||
|
||||
// 初始化页面
|
||||
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();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载文章失败:', error);
|
||||
renderDefaultArticles();
|
||||
} finally {
|
||||
isLoading = false;
|
||||
document.getElementById('loadingArticles').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染文章列表
|
||||
function renderArticles(articles) {
|
||||
const container = document.getElementById('articlesList');
|
||||
|
||||
// 如果是第一页,清空容器
|
||||
if (currentPage === 0) {
|
||||
container.innerHTML = '';
|
||||
}
|
||||
|
||||
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 defaultArticles = [
|
||||
{
|
||||
id: 1,
|
||||
title: "玩Android Material Design客户端发布",
|
||||
author: "Material Design",
|
||||
publishTime: Date.now() - 3600000, // 1小时前
|
||||
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, // 2小时前
|
||||
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, // 3小时前
|
||||
superChapterName: "Android",
|
||||
desc: "Material Design 3带来了动态颜色、设计令牌、组件更新等新特性。本文详细解析了这些新特性,并提供了在Android应用中的实现方法。",
|
||||
zan: 56,
|
||||
collect: false,
|
||||
comments: 24,
|
||||
fresh: false
|
||||
}
|
||||
];
|
||||
|
||||
renderArticles(defaultArticles);
|
||||
}
|
||||
|
||||
// 加载更多文章
|
||||
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>
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const article = articleDetails[articleId] || {
|
||||
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 - 修复版:已完成的页面直接跳转,未完成的显示提示
|
||||
function switchTab(tab) {
|
||||
// 更新选中状态
|
||||
document.querySelectorAll('.tab-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
|
||||
event.target.closest('.tab-item').classList.add('active');
|
||||
|
||||
// 根据tab进行跳转或提示
|
||||
switch(tab) {
|
||||
case 'home':
|
||||
// 首页已开发完成,当前页面
|
||||
// 不需要跳转
|
||||
break;
|
||||
case 'project':
|
||||
// 项目页面已开发完成,直接跳转
|
||||
window.location.href = '/projects_fixed.html';
|
||||
break;
|
||||
case 'wechat':
|
||||
// 公众号页面未开发
|
||||
window.location.href = '/wechat.html';
|
||||
break;
|
||||
case 'system':
|
||||
// 体系页面未开发
|
||||
alert('体系页面开发中...');
|
||||
break;
|
||||
case 'profile':
|
||||
// 我的页面未开发
|
||||
window.location.href = '/profile.html';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取相对时间
|
||||
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>
|
||||
Reference in New Issue
Block a user