Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

640 lines
28 KiB
HTML

<!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-placeholder { font-size: 16px; color: #757575; flex: 1; }
/* Banner */
.banner-container { padding: 16px; }
.banner { background: linear-gradient(135deg, #6200EE, #3700B3); height: 160px; border-radius: 16px; display: flex; flex-direction: column; justify-content: center; align-items: center; color: white; }
.banner-icon { font-size: 48px; margin-bottom: 12px; }
.banner-title { font-size: 20px; font-weight: 500; margin-bottom: 8px; }
.banner-desc { font-size: 14px; opacity: 0.9; }
/* 文章列表 */
.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; }
@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="showSearch()">🔍</div>
<div class="nav-icon" onclick="showMenu()">⋮</div>
</div>
</div>
<!-- 搜索栏 -->
<div class="search-bar">
<div class="search-container" onclick="showSearch()">
<div class="search-icon">🔍</div>
<div class="search-placeholder">搜索文章、项目、公众号...</div>
</div>
</div>
<!-- Banner -->
<div class="banner-container">
<div class="banner">
<div class="banner-icon">📱</div>
<div class="banner-title">玩Android Material Design</div>
<div class="banner-desc">最新技术文章,每日更新</div>
</div>
</div>
<!-- 文章列表 -->
<div class="articles-container">
<div class="section-title">最新文章</div>
<!-- 文章卡片会通过JavaScript动态生成 -->
<div id="articlesList"></div>
<!-- 加载更多 -->
<div class="load-more">
<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>
</div>
</div>
<script>
// 文章数据
const articles = [
{
id: 1,
title: "玩Android Material Design客户端发布",
author: "Material Design",
time: "刚刚",
category: "前端开发",
content: "玩Android Material Design客户端正式发布!这是一个基于Uniapp框架开发的Android应用,完全遵循Material Design 3设计规范。应用采用紫色主色系统,提供完整的Material Design组件库,包括卡片、按钮、导航栏、对话框等。",
fullContent: `
<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>
<h2>API集成</h2>
<p>应用集成了玩Android开放API,包括:</p>
<pre><code>// API接口示例
GET /api/banner/json // Banner轮播图
GET /api/hotkey/json // 搜索热词
GET /api/article/list/0/json // 文章列表
POST /api/user/login // 用户登录</code></pre>
<h2>开发体验</h2>
<p>项目采用模块化开发,代码结构清晰,易于维护和扩展。提供了完整的开发文档和示例代码。</p>
`,
fresh: true,
zan: 42,
collect: false,
comments: 12
},
{
id: 2,
title: "Uniapp框架Material Design实践指南",
author: "Uniapp团队",
time: "1小时前",
category: "Uniapp",
content: "本文详细介绍了如何在Uniapp框架中实现Material Design设计规范。从颜色系统、排版、图标到组件实现,提供了完整的实践指南和代码示例。",
fullContent: `
<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>
<h2>2. 排版系统</h2>
<p>Material Design使用Roboto字体,中文可以使用Noto Sans SC。需要设置合适的字体大小和行高:</p>
<pre><code>body {
font-family: 'Roboto', 'Noto Sans SC', sans-serif;
font-size: 16px;
line-height: 1.5;
}
h1 { font-size: 32px; font-weight: 400; }
h2 { font-size: 24px; font-weight: 500; }
h3 { font-size: 20px; font-weight: 500; }</code></pre>
<h2>3. 组件实现</h2>
<p>Material Design组件包括:</p>
<ul>
<li><strong>卡片(Card)</strong>:圆角、阴影、内边距</li>
<li><strong>按钮(Button)</strong>:填充按钮、轮廓按钮、文本按钮</li>
<li><strong>导航栏(App Bar)</strong>:固定位置、搜索栏、操作按钮</li>
<li><strong>底部导航(Bottom Navigation)</strong>:图标+文字、选中状态</li>
</ul>
<h2>4. 动效设计</h2>
<p>Material Design强调自然的动效,可以使用CSS transition和animation实现:</p>
<pre><code>.card {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}</code></pre>
`,
fresh: false,
zan: 28,
collect: true,
comments: 8
},
{
id: 3,
title: "Android Material Design 3新特性详解",
author: "Google",
time: "3小时前",
category: "Android",
content: "Material Design 3带来了动态颜色、设计令牌、组件更新等新特性。本文详细解析了这些新特性,并提供了在Android应用中的实现方法。",
fullContent: `
<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>
<h2>2. 设计令牌(Design Tokens)</h2>
<p>设计令牌是设计系统的变量,可以在代码中引用:</p>
<pre><code>// 在XML中使用
&lt;Button
android:background="@color/md_primary"
android:textColor="@color/md_on_primary" /&gt;</code></pre>
<h2>3. 组件更新</h2>
<p>Material Design 3更新了许多组件:</p>
<ul>
<li><strong>导航栏(Navigation Rail)</strong>:侧边导航,适合大屏幕设备</li>
<li><strong>搜索栏(Search Bar)</strong>:增强的搜索体验</li>
<li><strong日期选择器(Date Picker)</strong>:新的视觉设计</li>
<li><strong>时间选择器(Time Picker)</strong>:改进的用户界面</li>
</ul>
<h2>4. 动效系统</h2>
<p>Material Design 3引入了新的动效曲线和过渡效果:</p>
<pre><code>// 使用Material Motion
val motionSpec = MotionSpec()
.setDuration(300)
.setInterpolator(FastOutSlowInInterpolator())</code></pre>
<h2>5. 可访问性改进</h2>
<p>Material Design 3加强了可访问性支持:</p>
<ul>
<li>更高的对比度要求</li>
<li>更好的屏幕阅读器支持</li>
<li>键盘导航优化</li>
</ul>
`,
fresh: false,
zan: 56,
collect: false,
comments: 24
},
{
id: 4,
title: "玩Android API接口完整文档",
author: "玩Android",
time: "1天前",
category: "API文档",
content: "玩Android开放API提供了丰富的接口,包括文章、项目、公众号、用户系统等。本文是完整的API文档,包含所有接口的详细说明和调用示例。",
fullContent: `
<h1>玩Android API接口完整文档</h1>
<p>玩Android开放API为开发者提供了丰富的接口,可以用于构建各种Android学习应用。</p>
<h2>1. 基础信息</h2>
<ul>
<li><strong>Base URL</strong>: https://www.wanandroid.com</li>
<li><strong>数据格式</strong>: JSON</li>
<li><strong>请求方法</strong>: GET/POST</li>
<li><strong>编码</strong>: UTF-8</li>
</ul>
<h2>2. 文章相关接口</h2>
<h3>2.1 首页文章列表</h3>
<pre><code>GET /article/list/{page}/json
参数:
- page: 页码,从0开始
响应:
{
"data": {
"curPage": 0,
"datas": [...],
"offset": 0,
"over": false,
"pageCount": 5,
"size": 20,
"total": 20
},
"errorCode": 0,
"errorMsg": ""
}</code></pre>
<h3>2.2 Banner数据</h3>
<pre><code>GET /banner/json
响应:
{
"data": [
{
"desc": "描述",
"id": 1,
"imagePath": "图片URL",
"isVisible": 1,
"order": 0,
"title": "标题",
"type": 0,
"url": "跳转URL"
}
],
"errorCode": 0,
"errorMsg": ""
}</code></pre>
<h2>3. 项目相关接口</h2>
<h3>3.1 项目分类</h3>
<pre><code>GET /project/tree/json
响应:
{
"data": [
{
"children": [],
"courseId": 13,
"id": 294,
"name": "完整项目",
"order": 145000,
"parentChapterId": 293,
"visible": 1
}
],
"errorCode": 0,
"errorMsg": ""
}</code></pre>
<h2>4. 用户系统</h2>
<h3>4.1 用户登录</h3>
<pre><code>POST /user/login
参数:
- username: 用户名
- password: 密码
响应:
{
"data": {
"admin": false,
"chapterTops": [],
"collectIds": [],
"email": "",
"icon": "",
"id": 66720,
"nickname": "用户名",
"password": "",
"publicName": "用户名",
"token": "登录token",
"type": 0,
"username": "用户名"
},
"errorCode": 0,
"errorMsg": ""
}</code></pre>
<h2>5. 错误码说明</h2>
<ul>
<li><strong>0</strong>: 成功</li>
<li><strong>-1</strong>: 失败</li>
<li><strong>1001</strong>: 参数错误</li>
<li><strong>1002</strong>: 登录失效</li>
</ul>
`,
fresh: false,
zan: 89,
collect: true,
comments: 36
}
];
// 当前显示的页码
let currentPage = 0;
const articlesPerPage = 2;
// 初始化页面
document.addEventListener('DOMContentLoaded', function() {
renderArticles();
console.log('玩Android文章列表页面已加载');
console.log('公网访问: http://129.211.173.87:3000/index_with_articles.html');
});
// 渲染文章列表
function renderArticles() {
const container = document.getElementById('articlesList');
container.innerHTML = '';
const startIndex = currentPage * articlesPerPage;
const endIndex = startIndex + articlesPerPage;
const pageArticles = articles.slice(startIndex, endIndex);
pageArticles.forEach(article => {
const articleElement = document.createElement('div');
articleElement.className = 'article-card';
articleElement.setAttribute('data-id', article.id);
articleElement.onclick = () => showArticleDetail(article.id);
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">🕒 ${article.time}</div>
<div class="article-category">${article.category}</div>
</div>
<div class="article-content">${article.content}</div>
<div class="article-footer">
<div class="article-stats">
<div class="stat-item">
<span class="stat-icon">👍</span>
<span>${article.zan}</span>
</div>
<div class="stat-item">
<span class="stat-icon">💬</span>
<span>${article.comments}</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 showArticleDetail(articleId) {
const article = articles.find(a => a.id === articleId);
if (!article) return;
const detailContent = document.getElementById('detailContent');
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">🕒 ${article.time} • ${article.category}</div>
</div>
<div class="detail-body">${article.fullContent}</div>
<div class="detail-footer">
<div class="detail-actions">
<button class="action-btn" onclick="likeArticle(${article.id})">👍 点赞 (${article.zan})</button>
<button class="action-btn" onclick="collectArticle(${article.id})">${article.collect ? '⭐ 取消收藏' : '⭐ 收藏'}</button>
<button class="action-btn" onclick="shareArticle(${article.id})">📤 分享</button>
</div>
</div>
`;
document.getElementById('listPage').style.display = 'none';
document.getElementById('detailPage').style.display = 'block';
}
// 关闭文章详情
function closeDetail() {
document.getElementById('listPage').style.display = 'block';
document.getElementById('detailPage').style.display = 'none';
}
// 加载更多文章
function loadMoreArticles() {
currentPage++;
const startIndex = currentPage * articlesPerPage;
if (startIndex >= articles.length) {
alert('没有更多文章了');
currentPage--;
return;
}
renderArticles();
}
// 点赞文章
function likeArticle(articleId) {
const article = articles.find(a => a.id === articleId);
if (article) {
article.zan++;
alert(`已点赞!当前点赞数: ${article.zan}`);
renderArticles();
}
}
// 收藏文章
function collectArticle(articleId) {
const article = articles.find(a => a.id === articleId);
if (article) {
article.collect = !article.collect;
alert(article.collect ? '已收藏文章!' : '已取消收藏');
renderArticles();
}
}
// 分享文章
function shareArticle(articleId) {
const article = articles.find(a => a.id === articleId);
if (article) {
alert(`分享文章: ${article.title}\n\n分享功能开发中...`);
}
}
// 显示搜索
function showSearch() {
alert('搜索功能开发中...\n\n可以搜索文章、项目、公众号等内容');
}
// 显示菜单
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');
const tabNames = {
'home': '首页',
'project': '项目',
'wechat': '公众号',
'system': '体系',
'profile': '我的'
};
alert(`切换到: ${tabNames[tab]} 页面 (开发中)`);
}
</script>
</body>
</html>