Initial commit
This commit is contained in:
183
01_文档/原型设计/01_布局设计_简化主页面线框图.md
Normal file
183
01_文档/原型设计/01_布局设计_简化主页面线框图.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# 打飞机小程序 - 简化主页面线框图设计
|
||||
|
||||
## 设计说明
|
||||
根据用户需求,主页面简化为只包含以下元素:
|
||||
- 顶部:用户头像和昵称
|
||||
- 中间:游戏标题
|
||||
- 规则说明
|
||||
- 开始按钮
|
||||
|
||||
## 线框图设计方案
|
||||
|
||||
### 方案一:居中简约布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [头像] [昵称] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 打飞机对战 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 游戏规则 │ │
|
||||
│ │ 1. 双人轮流攻击对方棋盘 │ │
|
||||
│ │ 2. 击中对方飞机部件得分 │ │
|
||||
│ │ 3. 先击毁对方所有飞机获胜 │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 开始游戏 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 方案二:卡片式布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [头像] [昵称] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 打飞机对战小程序 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 📖 游戏规则 │ │
|
||||
│ │ │ │
|
||||
│ │ 双人轮流攻击对方棋盘 │ │
|
||||
│ │ 击中飞机部件得分 │ │
|
||||
│ │ 击毁所有飞机获胜 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 🚀 开始游戏 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 方案三:渐变背景布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [头像] [昵称] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ ✈️ 打飞机对战小程序 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 🎮 游戏规则 │ │
|
||||
│ │ │ │
|
||||
│ │ • 双人轮流攻击 │ │
|
||||
│ │ • 击中飞机部件得分 │ │
|
||||
│ │ • 击毁所有飞机获胜 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 🎯 开始游戏 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 方案四:图标装饰布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [头像] [昵称] │
|
||||
│ │
|
||||
│ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 打飞机对战小程序 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 📋 游戏规则 │ │
|
||||
│ │ 1. 双人轮流攻击棋盘 │ │
|
||||
│ │ 2. 击中飞机部件得分 │ │
|
||||
│ │ 3. 击毁所有飞机获胜 │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ ✈️ 🛩️ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 🚀 开始游戏 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 方案五:分步骤布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [头像] [昵称] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 打飞机对战小程序 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ 📖 游戏规则 │ │
|
||||
│ │ │ │
|
||||
│ │ 步骤1: 双人轮流攻击对方棋盘 │ │
|
||||
│ │ 步骤2: 击中飞机部件获得分数 │ │
|
||||
│ │ 步骤3: 先击毁对方所有飞机获胜 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 🎮 开始游戏 │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 设计建议
|
||||
|
||||
根据打飞机游戏的特性和目标用户群体,我推荐**方案二:卡片式布局**,原因如下:
|
||||
|
||||
1. **视觉层次清晰**:卡片设计让内容分区明确,用户一目了然
|
||||
2. **现代感强**:卡片式设计符合当前移动应用设计趋势
|
||||
3. **易于交互**:卡片按钮在移动端触控体验良好
|
||||
4. **扩展性好**:后续如需添加内容,卡片布局便于调整
|
||||
5. **适合游戏场景**:卡片式设计给人一种"游戏卡"的感觉,符合游戏主题
|
||||
|
||||
请确认您偏好的布局方案,我将进入下一阶段:**主题设计**,包括色彩方案、字体选择、间距系统等视觉元素的设计。
|
||||
606
01_文档/原型设计/入口页面.html
Normal file
606
01_文档/原型设计/入口页面.html
Normal file
@@ -0,0 +1,606 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>打飞机对战小程序</title>
|
||||
<meta name="theme-color" content="#0f1419">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
|
||||
<style>
|
||||
/* 设计变量 */
|
||||
:root {
|
||||
/* 主色调 - 深空科技蓝 */
|
||||
--primary-color: #6366f1;
|
||||
--primary-light: #8b5cf6;
|
||||
--primary-dark: #4f46e5;
|
||||
|
||||
/* 辅助色 - 科技青色 */
|
||||
--secondary-color: #40e0d0;
|
||||
--secondary-light: #26d0ce;
|
||||
|
||||
/* 强调色 - 橙色 */
|
||||
--accent-color: #f59e0b;
|
||||
--accent-light: #fbbf24;
|
||||
|
||||
/* 危险色 - 红色 */
|
||||
--danger-color: #ff4757;
|
||||
--danger-light: #ff6b6b;
|
||||
|
||||
/* 背景色系 - 深色渐变 */
|
||||
--bg-primary: #0f1419;
|
||||
--bg-secondary: #1a1d29;
|
||||
--bg-tertiary: #252837;
|
||||
--bg-elevated: #2d3142;
|
||||
|
||||
/* 渐变背景 */
|
||||
--gradient-bg: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 30%, #16213e 70%, #0f3460 100%);
|
||||
|
||||
/* 边框色系 */
|
||||
--border-primary: #3d4159;
|
||||
--border-secondary: #4a5073;
|
||||
--border-highlight: #6366f1;
|
||||
--border-accent: rgba(64, 224, 208, 0.3);
|
||||
|
||||
/* 文字色系 */
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #b4b7c9;
|
||||
--text-tertiary: #9ca3af;
|
||||
--text-disabled: #6b7280;
|
||||
|
||||
/* 移动端触摸区域尺寸 */
|
||||
--touch-target-min: 44px;
|
||||
--safe-area-padding: 20px;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
-webkit-user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Microsoft YaHei UI", sans-serif;
|
||||
background: var(--gradient-bg);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
/* 安全区域适配 */
|
||||
.safe-area {
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
/* 动态星空背景 */
|
||||
.star-field {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.star {
|
||||
position: absolute;
|
||||
background: rgba(64, 224, 208, 0.8);
|
||||
border-radius: 50%;
|
||||
animation: twinkle 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 0.3; transform: scale(1); }
|
||||
50% { opacity: 1; transform: scale(1.2); }
|
||||
}
|
||||
|
||||
/* 主容器 */
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 顶部用户信息栏 */
|
||||
.user-header {
|
||||
background: rgba(26, 29, 41, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
padding: 15px var(--safe-area-padding);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
||||
}
|
||||
|
||||
.user-details h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.user-level {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.level-badge {
|
||||
background: linear-gradient(135deg, var(--accent-color) 0%, var(--accent-light) 100%);
|
||||
color: white;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.settings-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: rgba(99, 102, 241, 0.15);
|
||||
border: 1px solid var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.settings-btn:hover {
|
||||
background: rgba(99, 102, 241, 0.25);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.settings-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--safe-area-padding);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 游戏标题卡片 */
|
||||
.title-card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 16px;
|
||||
padding: 30px 20px;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 30px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.title-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color), var(--accent-color));
|
||||
animation: shimmer 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0%, 100% { transform: translateX(-100%); }
|
||||
50% { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
.game-title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 50%, var(--secondary-color) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.game-subtitle {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 飞机装饰 */
|
||||
.plane-decoration {
|
||||
position: absolute;
|
||||
opacity: 0.1;
|
||||
font-size: 60px;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.plane-decoration.top-left {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.plane-decoration.top-right {
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.plane-decoration.bottom-left {
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.plane-decoration.bottom-right {
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
transform: rotate(-135deg);
|
||||
}
|
||||
|
||||
/* 游戏规则卡片 */
|
||||
.rules-card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 16px;
|
||||
padding: 25px;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.rules-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.rules-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: linear-gradient(135deg, var(--secondary-color) 0%, var(--secondary-light) 100%);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
color: #1a1a2e;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.rules-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.rules-content {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.rule-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.rule-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.rule-number {
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* 开始按钮 */
|
||||
.start-button {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
min-height: var(--touch-target-min);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
padding: 16px 32px;
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.4);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.start-button::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.3s, height 0.3s;
|
||||
}
|
||||
|
||||
.start-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 12px 35px rgba(99, 102, 241, 0.5);
|
||||
}
|
||||
|
||||
.start-button:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4);
|
||||
}
|
||||
|
||||
.start-button:active::before {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 375px) {
|
||||
.user-header {
|
||||
padding: 12px var(--safe-area-padding);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.game-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.start-button {
|
||||
font-size: 16px;
|
||||
min-height: 42px;
|
||||
padding: 14px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 640px) {
|
||||
.main-content {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.title-card, .rules-card {
|
||||
margin-bottom: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.game-title {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 高对比度支持 */
|
||||
@media (prefers-contrast: high) {
|
||||
:root {
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #e5e5e5;
|
||||
--border-primary: #ffffff;
|
||||
--bg-secondary: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 减少动画偏好 */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 暗色模式强制支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="safe-area">
|
||||
<!-- 动态星空背景 -->
|
||||
<div class="star-field" id="starField"></div>
|
||||
|
||||
<div class="app-container">
|
||||
<!-- 顶部用户信息栏 -->
|
||||
<header class="user-header">
|
||||
<div class="user-info">
|
||||
<div class="user-avatar">👤</div>
|
||||
<div class="user-details">
|
||||
<h3>玩家昵称</h3>
|
||||
</div>
|
||||
</div>
|
||||
<button class="settings-btn">⚙️</button>
|
||||
</header>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<main class="main-content">
|
||||
<!-- 游戏标题卡片 -->
|
||||
<div class="title-card">
|
||||
<div class="plane-decoration top-left">✈️</div>
|
||||
<div class="plane-decoration top-right">✈️</div>
|
||||
<div class="plane-decoration bottom-left">✈️</div>
|
||||
<div class="plane-decoration bottom-right">✈️</div>
|
||||
|
||||
<h1 class="game-title">打飞机对战</h1>
|
||||
<p class="game-subtitle">经典策略游戏,智慧与技巧的较量</p>
|
||||
</div>
|
||||
|
||||
<!-- 游戏规则卡片 -->
|
||||
<div class="rules-card">
|
||||
<div class="rules-header">
|
||||
<div class="rules-icon">📖</div>
|
||||
<h2 class="rules-title">游戏规则</h2>
|
||||
</div>
|
||||
<div class="rules-content">
|
||||
<div class="rule-item">
|
||||
<div class="rule-number">1</div>
|
||||
<div>双人轮流攻击对方棋盘,猜测飞机位置</div>
|
||||
</div>
|
||||
<div class="rule-item">
|
||||
<div class="rule-number">2</div>
|
||||
<div>击中飞机部件获得分数,未命中则轮到对手</div>
|
||||
</div>
|
||||
<div class="rule-item">
|
||||
<div class="rule-number">3</div>
|
||||
<div>先击毁对方所有飞机的玩家获胜</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 开始按钮 -->
|
||||
<button class="start-button" id="startGame">
|
||||
<span class="button-icon">🚀</span>
|
||||
开始游戏
|
||||
</button>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 创建动态星空背景
|
||||
function createStarField() {
|
||||
const starField = document.getElementById('starField');
|
||||
const numStars = 50;
|
||||
|
||||
for (let i = 0; i < numStars; i++) {
|
||||
const star = document.createElement('div');
|
||||
star.className = 'star';
|
||||
star.style.width = Math.random() * 3 + 'px';
|
||||
star.style.height = star.style.width;
|
||||
star.style.left = Math.random() * 100 + '%';
|
||||
star.style.top = Math.random() * 100 + '%';
|
||||
star.style.animationDelay = Math.random() * 3 + 's';
|
||||
starField.appendChild(star);
|
||||
}
|
||||
}
|
||||
|
||||
// 触觉反馈
|
||||
function addHapticFeedback(element) {
|
||||
element.addEventListener('click', () => {
|
||||
if ('vibrate' in navigator) {
|
||||
navigator.vibrate(10);
|
||||
}
|
||||
document.body.classList.add('haptic-feedback');
|
||||
setTimeout(() => document.body.classList.remove('haptic-feedback'), 100);
|
||||
});
|
||||
}
|
||||
|
||||
// 开始游戏按钮点击事件
|
||||
document.getElementById('startGame').addEventListener('click', () => {
|
||||
// 这里可以添加跳转到游戏页面的逻辑
|
||||
console.log('开始游戏');
|
||||
if ('vibrate' in navigator) {
|
||||
navigator.vibrate(20);
|
||||
}
|
||||
});
|
||||
|
||||
// 设置按钮点击事件
|
||||
document.querySelector('.settings-btn').addEventListener('click', () => {
|
||||
console.log('打开设置');
|
||||
if ('vibrate' in navigator) {
|
||||
navigator.vibrate(10);
|
||||
}
|
||||
});
|
||||
|
||||
// 页面加载完成后初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
createStarField();
|
||||
|
||||
// 为所有可点击元素添加触觉反馈
|
||||
addHapticFeedback(document.getElementById('startGame'));
|
||||
addHapticFeedback(document.querySelector('.settings-btn'));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
630
01_文档/原型设计/准备页面.html
Normal file
630
01_文档/原型设计/准备页面.html
Normal file
@@ -0,0 +1,630 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>飞机布置 - 新版</title>
|
||||
<meta name="theme-color" content="#0f1419">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #6366f1;
|
||||
--primary-light: #8b5cf6;
|
||||
--accent-color: #f59e0b;
|
||||
--danger-color: #ef4444;
|
||||
--success-color: #10b981;
|
||||
--bg-primary: #0f1419;
|
||||
--bg-secondary: #1a1d29;
|
||||
--bg-tertiary: #252837;
|
||||
--border-primary: #3d4159;
|
||||
--border-secondary: #4a5073;
|
||||
--border-highlight: #6366f1;
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #b4b7c9;
|
||||
--text-tertiary: #9ca3af;
|
||||
--text-disabled: #6b7280;
|
||||
--cell-size: min(8.5vw, 38px);
|
||||
--safe-area-padding: 16px;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
html, body { height: 100%; overflow: hidden; -webkit-user-select: none; user-select: none; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Microsoft YaHei UI", sans-serif;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
touch-action: none;
|
||||
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
||||
}
|
||||
|
||||
.app-container { display: flex; flex-direction: column; height: 100%; }
|
||||
|
||||
.top-nav {
|
||||
padding: 12px var(--safe-area-padding);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
background: rgba(15, 20, 25, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
padding: var(--safe-area-padding);
|
||||
}
|
||||
|
||||
.board-wrapper { position: relative; }
|
||||
.game-board {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, var(--cell-size));
|
||||
grid-template-rows: repeat(10, var(--cell-size));
|
||||
gap: 1px;
|
||||
background: var(--border-primary);
|
||||
border: 1px solid var(--border-primary);
|
||||
}
|
||||
.board-cell {
|
||||
background: var(--bg-secondary);
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.board-cell:active { background-color: var(--border-highlight); }
|
||||
.board-cell.plane-part { background-color: var(--primary-color); }
|
||||
.board-cell.plane-head { background-color: var(--accent-color); }
|
||||
.board-cell.plane-body { background-color: var(--primary-light); }
|
||||
.board-cell.plane-wing { background-color: var(--primary-light); }
|
||||
.board-cell.plane-tail { background-color: var(--primary-color); }
|
||||
.board-cell.selected { box-shadow: inset 0 0 0 2px var(--success-color); z-index: 1; }
|
||||
|
||||
.col-label, .row-label {
|
||||
position: absolute;
|
||||
font-size: 10px;
|
||||
color: var(--text-tertiary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.col-label { top: -20px; height: 15px; width: var(--cell-size); }
|
||||
.row-label { left: -20px; width: 15px; height: var(--cell-size); }
|
||||
|
||||
.controls-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: var(--safe-area-padding);
|
||||
background: var(--bg-secondary);
|
||||
border-top: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.main-controls {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.direction-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.direction-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 44px);
|
||||
grid-template-rows: repeat(3, 44px);
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.direction-grid button {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border-primary);
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.plane-selection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.confirmation-group {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.plane-btn.selected {
|
||||
background-color: var(--success-color) !important;
|
||||
border-color: var(--success-color) !important;
|
||||
box-shadow: 0 0 10px rgba(16, 185, 129, 0.5);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.status-display {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border-primary);
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
}
|
||||
.btn:disabled {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-disabled);
|
||||
border-color: var(--border-primary);
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.btn:active:not(:disabled) { transform: scale(0.95); }
|
||||
|
||||
.plane-btn.placed { background-color: var(--primary-color); border-color: var(--primary-light); }
|
||||
.plane-btn.selected { background-color: var(--success-color); border-color: var(--success-color); }
|
||||
|
||||
.confirmation-group .btn-primary { background-color: var(--primary-color); }
|
||||
.confirmation-group .btn-danger { background-color: var(--danger-color); }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<header class="top-nav">准备页面</header>
|
||||
|
||||
<main class="main-content">
|
||||
<div class="board-wrapper" id="boardWrapper">
|
||||
<div class="game-board" id="gameBoard"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="controls-area">
|
||||
<div class="status-display" id="statusDisplay">请点击棋盘放置飞机</div>
|
||||
|
||||
<div class="main-controls">
|
||||
<div class="direction-control">
|
||||
<div class="direction-grid">
|
||||
<div></div>
|
||||
<button class="btn" id="moveUpBtn">↑</button>
|
||||
<button class="btn" id="deleteBtn">🗑️</button>
|
||||
|
||||
<button class="btn" id="moveLeftBtn">←</button>
|
||||
<button class="btn" id="rotateBtn">↻</button>
|
||||
<button class="btn" id="moveRightBtn">→</button>
|
||||
|
||||
<div></div>
|
||||
<button class="btn" id="moveDownBtn">↓</button>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="plane-selection">
|
||||
<button class="btn plane-btn" id="planeBtn1" data-plane-id="1">飞机1</button>
|
||||
<button class="btn plane-btn" id="planeBtn2" data-plane-id="2">飞机2</button>
|
||||
<button class="btn plane-btn" id="planeBtn3" data-plane-id="3">飞机3</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="confirmation-group">
|
||||
<button class="btn" id="randomBtn">🎲 随机</button>
|
||||
<button class="btn btn-danger" id="resetBtn">🔄 重置</button>
|
||||
<button class="btn btn-primary" id="doneBtn">✓ 完成</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
class MobilePlacementGame {
|
||||
constructor() {
|
||||
this.BOARD_SIZE = 10;
|
||||
this.PLANE_COUNT = 3;
|
||||
this.boardState = Array(this.BOARD_SIZE).fill(null).map(() => Array(this.BOARD_SIZE).fill(0));
|
||||
this.planes = [];
|
||||
this.selectedPlaneId = null;
|
||||
|
||||
this.dom = {
|
||||
board: document.getElementById('gameBoard'),
|
||||
boardWrapper: document.getElementById('boardWrapper'),
|
||||
statusDisplay: document.getElementById('statusDisplay'),
|
||||
planeBtns: [
|
||||
document.getElementById('planeBtn1'),
|
||||
document.getElementById('planeBtn2'),
|
||||
document.getElementById('planeBtn3'),
|
||||
],
|
||||
moveUpBtn: document.getElementById('moveUpBtn'),
|
||||
moveDownBtn: document.getElementById('moveDownBtn'),
|
||||
moveLeftBtn: document.getElementById('moveLeftBtn'),
|
||||
moveRightBtn: document.getElementById('moveRightBtn'),
|
||||
rotateBtn: document.getElementById('rotateBtn'),
|
||||
deleteBtn: document.getElementById('deleteBtn'),
|
||||
randomBtn: document.getElementById('randomBtn'),
|
||||
resetBtn: document.getElementById('resetBtn'),
|
||||
doneBtn: document.getElementById('doneBtn'),
|
||||
};
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.createBoard();
|
||||
this.createPlanes();
|
||||
this.bindEvents();
|
||||
this.updateUI();
|
||||
console.log("游戏已初始化");
|
||||
}
|
||||
|
||||
createBoard() {
|
||||
this.dom.board.innerHTML = '';
|
||||
for (let r = 0; r < this.BOARD_SIZE; r++) {
|
||||
for (let c = 0; c < this.BOARD_SIZE; c++) {
|
||||
const cell = document.createElement('div');
|
||||
cell.className = 'board-cell';
|
||||
cell.dataset.row = r;
|
||||
cell.dataset.col = c;
|
||||
this.dom.board.appendChild(cell);
|
||||
}
|
||||
}
|
||||
|
||||
const labelsWrapper = document.createElement('div');
|
||||
labelsWrapper.className = 'labels';
|
||||
for (let i = 0; i < this.BOARD_SIZE; i++) {
|
||||
const colLabel = document.createElement('div');
|
||||
colLabel.className = 'col-label';
|
||||
colLabel.textContent = String.fromCharCode(65 + i);
|
||||
colLabel.style.left = `calc(${(i + 0.5)} * var(--cell-size))`;
|
||||
labelsWrapper.appendChild(colLabel);
|
||||
|
||||
const rowLabel = document.createElement('div');
|
||||
rowLabel.className = 'row-label';
|
||||
rowLabel.textContent = i + 1;
|
||||
rowLabel.style.top = `calc(${(i + 0.5)} * var(--cell-size))`;
|
||||
labelsWrapper.appendChild(rowLabel);
|
||||
}
|
||||
this.dom.boardWrapper.appendChild(labelsWrapper);
|
||||
}
|
||||
|
||||
createPlanes() {
|
||||
this.planes = [];
|
||||
for(let i = 1; i <= this.PLANE_COUNT; i++) {
|
||||
this.planes.push({
|
||||
id: i,
|
||||
center: null,
|
||||
direction: 'up',
|
||||
isPlaced: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.dom.board.addEventListener('click', this.handleBoardClick.bind(this));
|
||||
this.dom.planeBtns.forEach(btn => btn.addEventListener('click', this.handlePlaneBtnClick.bind(this)));
|
||||
this.dom.moveUpBtn.addEventListener('click', () => this.moveSelectedPlane(0, -1));
|
||||
this.dom.moveDownBtn.addEventListener('click', () => this.moveSelectedPlane(0, 1));
|
||||
this.dom.moveLeftBtn.addEventListener('click', () => this.moveSelectedPlane(-1, 0));
|
||||
this.dom.moveRightBtn.addEventListener('click', () => this.moveSelectedPlane(1, 0));
|
||||
this.dom.rotateBtn.addEventListener('click', this.rotateSelectedPlane.bind(this));
|
||||
this.dom.deleteBtn.addEventListener('click', this.deleteSelectedPlane.bind(this));
|
||||
this.dom.randomBtn.addEventListener('click', this.randomPlacePlane.bind(this));
|
||||
this.dom.resetBtn.addEventListener('click', this.resetGame.bind(this));
|
||||
this.dom.doneBtn.addEventListener('click', this.completePlacement.bind(this));
|
||||
}
|
||||
|
||||
handleBoardClick(e) {
|
||||
const cell = e.target.closest('.board-cell');
|
||||
if (!cell) return;
|
||||
|
||||
const row = parseInt(cell.dataset.row);
|
||||
const col = parseInt(cell.dataset.col);
|
||||
const cellContent = this.boardState[row][col];
|
||||
|
||||
if (cellContent > 0) { // Clicked on an existing plane
|
||||
this.selectedPlaneId = cellContent;
|
||||
} else { // Clicked on an empty cell
|
||||
const unplacedPlane = this.planes.find(p => !p.isPlaced);
|
||||
if (unplacedPlane) {
|
||||
this.tryPlacePlane(unplacedPlane.id, {x: col, y: row}, 'up');
|
||||
} else {
|
||||
this.updateStatus("所有飞机都已放置。");
|
||||
}
|
||||
}
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
handlePlaneBtnClick(e) {
|
||||
const planeId = parseInt(e.target.dataset.planeId);
|
||||
const plane = this.planes.find(p => p.id === planeId);
|
||||
if (plane && plane.isPlaced) {
|
||||
this.selectedPlaneId = (this.selectedPlaneId === planeId) ? null : planeId;
|
||||
this.updateUI();
|
||||
} else {
|
||||
this.updateStatus(`飞机 ${planeId} 尚未放置。`);
|
||||
}
|
||||
}
|
||||
|
||||
tryPlacePlane(planeId, center, direction) {
|
||||
const plane = this.planes.find(p => p.id === planeId);
|
||||
if (!plane) return;
|
||||
|
||||
const directions = ['up', 'right', 'down', 'left'];
|
||||
const startIndex = directions.indexOf(direction);
|
||||
let placedSuccessfully = false;
|
||||
let usedDirection = direction;
|
||||
|
||||
// 尝试所有方向,从指定方向开始
|
||||
for (let i = 0; i < directions.length; i++) {
|
||||
const currentDirection = directions[(startIndex + i) % 4];
|
||||
const positions = this.getPlanePositions(center, currentDirection);
|
||||
|
||||
if (this.isPlacementValid(positions, planeId)) {
|
||||
// Clear old position if any
|
||||
this.clearPlaneFromBoard(planeId);
|
||||
|
||||
plane.center = center;
|
||||
plane.direction = currentDirection;
|
||||
plane.isPlaced = true;
|
||||
|
||||
positions.forEach(p => { this.boardState[p.y][p.x] = planeId; });
|
||||
this.selectedPlaneId = planeId;
|
||||
placedSuccessfully = true;
|
||||
usedDirection = currentDirection;
|
||||
|
||||
// 如果使用了不同于初始请求的方向,显示特殊提示
|
||||
if (currentDirection !== direction) {
|
||||
this.updateStatus(`飞机 ${planeId} 已放置,已自动旋转为 ${this.getDirectionName(currentDirection)} 方向。`);
|
||||
} else {
|
||||
this.updateStatus(`飞机 ${planeId} 操作成功。`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!placedSuccessfully) {
|
||||
this.updateStatus(`操作无效: 所有方向都存在位置冲突或越界。`);
|
||||
}
|
||||
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
moveSelectedPlane(dx, dy) {
|
||||
if (!this.selectedPlaneId) return;
|
||||
const plane = this.planes.find(p => p.id === this.selectedPlaneId);
|
||||
const newCenter = { x: plane.center.x + dx, y: plane.center.y + dy };
|
||||
this.tryPlacePlane(plane.id, newCenter, plane.direction);
|
||||
}
|
||||
|
||||
rotateSelectedPlane() {
|
||||
if (!this.selectedPlaneId) return;
|
||||
const plane = this.planes.find(p => p.id === this.selectedPlaneId);
|
||||
const directions = ['up', 'right', 'down', 'left'];
|
||||
const currentIndex = directions.indexOf(plane.direction);
|
||||
const nextDirection = directions[(currentIndex + 1) % 4];
|
||||
this.tryPlacePlane(plane.id, plane.center, nextDirection);
|
||||
}
|
||||
|
||||
deleteSelectedPlane() {
|
||||
if (!this.selectedPlaneId) return;
|
||||
const planeId = this.selectedPlaneId;
|
||||
this.clearPlaneFromBoard(planeId);
|
||||
const plane = this.planes.find(p => p.id === planeId);
|
||||
plane.isPlaced = false;
|
||||
plane.center = null;
|
||||
this.selectedPlaneId = null;
|
||||
this.updateStatus(`飞机 ${planeId} 已移除。`);
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
randomPlacePlane() {
|
||||
const unplacedPlane = this.planes.find(p => !p.isPlaced);
|
||||
if (!unplacedPlane) {
|
||||
this.updateStatus("所有飞机都已放置。");
|
||||
return;
|
||||
}
|
||||
|
||||
// 尝试随机位置和方向
|
||||
const directions = ['up', 'right', 'down', 'left'];
|
||||
const maxAttempts = 100; // 防止无限循环
|
||||
let placed = false;
|
||||
|
||||
for (let attempt = 0; attempt < maxAttempts && !placed; attempt++) {
|
||||
const randomX = Math.floor(Math.random() * this.BOARD_SIZE);
|
||||
const randomY = Math.floor(Math.random() * this.BOARD_SIZE);
|
||||
const randomDirection = directions[Math.floor(Math.random() * directions.length)];
|
||||
|
||||
const center = { x: randomX, y: randomY };
|
||||
const positions = this.getPlanePositions(center, randomDirection);
|
||||
|
||||
if (this.isPlacementValid(positions, unplacedPlane.id)) {
|
||||
this.clearPlaneFromBoard(unplacedPlane.id);
|
||||
|
||||
unplacedPlane.center = center;
|
||||
unplacedPlane.direction = randomDirection;
|
||||
unplacedPlane.isPlaced = true;
|
||||
|
||||
positions.forEach(p => { this.boardState[p.y][p.x] = unplacedPlane.id; });
|
||||
this.selectedPlaneId = unplacedPlane.id;
|
||||
placed = true;
|
||||
|
||||
this.updateStatus(`飞机 ${unplacedPlane.id} 已随机放置在 ${String.fromCharCode(65 + randomX)}${randomY + 1},方向为${this.getDirectionName(randomDirection)}。`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!placed) {
|
||||
this.updateStatus(`无法为飞机 ${unplacedPlane.id} 找到合适的随机位置。`);
|
||||
}
|
||||
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
resetGame() {
|
||||
this.boardState = Array(this.BOARD_SIZE).fill(null).map(() => Array(this.BOARD_SIZE).fill(0));
|
||||
this.createPlanes();
|
||||
this.selectedPlaneId = null;
|
||||
this.updateStatus("已重置棋盘,请重新放置。");
|
||||
this.updateUI();
|
||||
}
|
||||
|
||||
completePlacement() {
|
||||
if(this.planes.every(p => p.isPlaced)) {
|
||||
this.updateStatus("准备就绪,等待对手...");
|
||||
localStorage.setItem('playerPlanes', JSON.stringify(this.planes));
|
||||
// 禁用所有按钮
|
||||
Object.values(this.dom).flat().forEach(el => {
|
||||
if(el.tagName === 'BUTTON') el.disabled = true;
|
||||
});
|
||||
} else {
|
||||
this.updateStatus("请先放置所有飞机。");
|
||||
}
|
||||
}
|
||||
|
||||
clearPlaneFromBoard(planeId) {
|
||||
for (let r = 0; r < this.BOARD_SIZE; r++) {
|
||||
for (let c = 0; c < this.BOARD_SIZE; c++) {
|
||||
if (this.boardState[r][c] === planeId) {
|
||||
this.boardState[r][c] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanePositions(center, direction) {
|
||||
const geometry = {
|
||||
up: [
|
||||
{ x: 0, y: -2, type: 'head' },
|
||||
{ x: -2, y: -1, type: 'wing' }, { x: -1, y: -1, type: 'wing' }, { x: 0, y: -1, type: 'wing' }, { x: 1, y: -1, type: 'wing' }, { x: 2, y: -1, type: 'wing' },
|
||||
{ x: 0, y: 0, type: 'body' }, { x: 0, y: 1, type: 'body' },
|
||||
{ x: -1, y: 2, type: 'tail' }, { x: 0, y: 2, type: 'tail' }, { x: 1, y: 2, type: 'tail' }
|
||||
],
|
||||
down: [
|
||||
{ x: 0, y: 2, type: 'head' },
|
||||
{ x: -2, y: 1, type: 'wing' }, { x: -1, y: 1, type: 'wing' }, { x: 0, y: 1, type: 'wing' }, { x: 1, y: 1, type: 'wing' }, { x: 2, y: 1, type: 'wing' },
|
||||
{ x: 0, y: 0, type: 'body' }, { x: 0, y: -1, type: 'body' },
|
||||
{ x: -1, y: -2, type: 'tail' }, { x: 0, y: -2, type: 'tail' }, { x: 1, y: -2, type: 'tail' }
|
||||
],
|
||||
left: [
|
||||
{ x: -2, y: 0, type: 'head' },
|
||||
{ x: -1, y: -2, type: 'wing' }, { x: -1, y: -1, type: 'wing' }, { x: -1, y: 0, type: 'wing' }, { x: -1, y: 1, type: 'wing' }, { x: -1, y: 2, type: 'wing' },
|
||||
{ x: 0, y: 0, type: 'body' }, { x: 1, y: 0, type: 'body' },
|
||||
{ x: 2, y: -1, type: 'tail' }, { x: 2, y: 0, type: 'tail' }, { x: 2, y: 1, type: 'tail' }
|
||||
],
|
||||
right: [
|
||||
{ x: 2, y: 0, type: 'head' },
|
||||
{ x: 1, y: -2, type: 'wing' }, { x: 1, y: -1, type: 'wing' }, { x: 1, y: 0, type: 'wing' }, { x: 1, y: 1, type: 'wing' }, { x: 1, y: 2, type: 'wing' },
|
||||
{ x: 0, y: 0, type: 'body' }, { x: -1, y: 0, type: 'body' },
|
||||
{ x: -2, y: -1, type: 'tail' }, { x: -2, y: 0, type: 'tail' }, { x: -2, y: 1, type: 'tail' }
|
||||
]
|
||||
};
|
||||
|
||||
const offsets = geometry[direction];
|
||||
if (!offsets) return [];
|
||||
|
||||
return offsets.map(o => ({ x: center.x + o.x, y: center.y + o.y, type: o.type }));
|
||||
}
|
||||
|
||||
isPlacementValid(positions, planeId) {
|
||||
for (const pos of positions) {
|
||||
if (pos.x < 0 || pos.x >= this.BOARD_SIZE || pos.y < 0 || pos.y >= this.BOARD_SIZE) return false; // Out of bounds
|
||||
const occupyingId = this.boardState[pos.y][pos.x];
|
||||
if (occupyingId !== 0 && occupyingId !== planeId) return false; // Collision
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getDirectionName(direction) {
|
||||
const directionNames = {
|
||||
'up': '向上',
|
||||
'right': '向右',
|
||||
'down': '向下',
|
||||
'left': '向左'
|
||||
};
|
||||
return directionNames[direction] || direction;
|
||||
}
|
||||
|
||||
updateUI() {
|
||||
// Update board
|
||||
for (let r = 0; r < this.BOARD_SIZE; r++) {
|
||||
for (let c = 0; c < this.BOARD_SIZE; c++) {
|
||||
const cell = this.dom.board.children[r * this.BOARD_SIZE + c];
|
||||
cell.className = 'board-cell';
|
||||
const planeId = this.boardState[r][c];
|
||||
if (planeId > 0) {
|
||||
cell.classList.add('plane-part');
|
||||
const plane = this.planes.find(p => p.id === planeId);
|
||||
|
||||
if (plane && plane.isPlaced && plane.center) {
|
||||
const planePositions = this.getPlanePositions(plane.center, plane.direction);
|
||||
const part = planePositions.find(p => p.x === c && p.y === r);
|
||||
|
||||
if (part && part.type) {
|
||||
cell.classList.add(`plane-${part.type}`); // Adds plane-head, plane-body etc.
|
||||
}
|
||||
if (planeId === this.selectedPlaneId) {
|
||||
cell.classList.add('selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update plane buttons
|
||||
this.dom.planeBtns.forEach(btn => {
|
||||
const planeId = parseInt(btn.dataset.planeId);
|
||||
const plane = this.planes.find(p => p.id === planeId);
|
||||
btn.classList.remove('placed', 'selected');
|
||||
if (plane.isPlaced) btn.classList.add('placed');
|
||||
if (planeId === this.selectedPlaneId) btn.classList.add('selected');
|
||||
});
|
||||
|
||||
// Update manipulation buttons
|
||||
const isPlaneSelected = this.selectedPlaneId !== null;
|
||||
const hasUnplacedPlane = this.planes.some(p => !p.isPlaced);
|
||||
this.dom.moveUpBtn.disabled = !isPlaneSelected;
|
||||
this.dom.moveDownBtn.disabled = !isPlaneSelected;
|
||||
this.dom.moveLeftBtn.disabled = !isPlaneSelected;
|
||||
this.dom.moveRightBtn.disabled = !isPlaneSelected;
|
||||
this.dom.rotateBtn.disabled = !isPlaneSelected;
|
||||
this.dom.deleteBtn.disabled = !isPlaneSelected;
|
||||
this.dom.randomBtn.disabled = !hasUnplacedPlane;
|
||||
|
||||
// Update confirmation buttons
|
||||
this.dom.doneBtn.disabled = !this.planes.every(p => p.isPlaced);
|
||||
}
|
||||
|
||||
updateStatus(message) {
|
||||
this.dom.statusDisplay.textContent = message;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => new MobilePlacementGame());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
677
01_文档/原型设计/移动端控件样式示例.css
Normal file
677
01_文档/原型设计/移动端控件样式示例.css
Normal file
@@ -0,0 +1,677 @@
|
||||
/* 移动端控件样式设计规范 - 示例CSS */
|
||||
|
||||
:root {
|
||||
/* 主色调 - 深空科技蓝 */
|
||||
--primary-color: #6366f1;
|
||||
--primary-light: #8b5cf6;
|
||||
--primary-dark: #4f46e5;
|
||||
|
||||
/* 辅助色 - 科技青色 */
|
||||
--secondary-color: #40e0d0;
|
||||
--secondary-light: #26d0ce;
|
||||
|
||||
/* 强调色 - 橙色 */
|
||||
--accent-color: #f59e0b;
|
||||
--accent-light: #fbbf24;
|
||||
|
||||
/* 危险色 - 红色 */
|
||||
--danger-color: #ff4757;
|
||||
--danger-light: #ff6b6b;
|
||||
|
||||
/* 背景色系 - 深色渐变 */
|
||||
--bg-primary: #0f1419;
|
||||
--bg-secondary: #1a1d29;
|
||||
--bg-tertiary: #252837;
|
||||
--bg-elevated: #2d3142;
|
||||
|
||||
/* 渐变背景 */
|
||||
--gradient-bg: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 30%, #16213e 70%, #0f3460 100%);
|
||||
|
||||
/* 边框色系 */
|
||||
--border-primary: #3d4159;
|
||||
--border-secondary: #4a5073;
|
||||
--border-highlight: #6366f1;
|
||||
--border-accent: rgba(64, 224, 208, 0.3);
|
||||
|
||||
/* 文字色系 */
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #b4b7c9;
|
||||
--text-tertiary: #9ca3af;
|
||||
--text-disabled: #6b7280;
|
||||
|
||||
/* 移动端触摸区域尺寸 */
|
||||
--touch-target-min: 44px;
|
||||
--safe-area-padding: 20px;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
-webkit-user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Microsoft YaHei UI", sans-serif;
|
||||
background: var(--gradient-bg);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
/* PWA 支持的安全区域适配 */
|
||||
.safe-area {
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
/* 动态星空背景 */
|
||||
.star-field {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.star {
|
||||
position: absolute;
|
||||
background: rgba(64, 224, 208, 0.8);
|
||||
border-radius: 50%;
|
||||
animation: twinkle 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 0.3; transform: scale(1); }
|
||||
50% { opacity: 1; transform: scale(1.2); }
|
||||
}
|
||||
|
||||
/* 主容器 - 全屏布局 */
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 状态栏 */
|
||||
.status-bar {
|
||||
background: rgba(26, 29, 41, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
padding: 8px var(--safe-area-padding);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.network-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.connection-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--secondary-color);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.4; transform: scale(1.3); }
|
||||
}
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--safe-area-padding);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 页签切换容器 */
|
||||
.tab-container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
display: flex;
|
||||
background: var(--bg-tertiary);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
color: var(--primary-color);
|
||||
background: var(--bg-secondary);
|
||||
border-bottom: 2px solid var(--primary-color);
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding: 20px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-pane.active {
|
||||
display: block;
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* 按钮控件 */
|
||||
.btn {
|
||||
min-height: var(--touch-target-min);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 14px 24px;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 按钮触摸反馈效果 */
|
||||
.btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.3s, height 0.3s;
|
||||
}
|
||||
|
||||
.btn:active::before {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
|
||||
color: #ffffff;
|
||||
box-shadow: 0 4px 16px rgba(99, 102, 241, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary:hover, .btn-primary:focus {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.4);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 8px rgba(99, 102, 241, 0.4);
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: linear-gradient(135deg, var(--secondary-color), var(--secondary-light));
|
||||
color: #1a1a2e;
|
||||
box-shadow: 0 4px 16px rgba(64, 224, 208, 0.3);
|
||||
}
|
||||
|
||||
.btn-success:hover, .btn-success:focus {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(64, 224, 208, 0.4);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: rgba(99, 102, 241, 0.15);
|
||||
color: var(--primary-color);
|
||||
border: 1px solid var(--primary-color);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.btn-secondary:hover, .btn-secondary:focus {
|
||||
background: rgba(99, 102, 241, 0.25);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 按钮组 */
|
||||
.action-buttons {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 卡片控件 */
|
||||
.card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
margin-top: 16px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--border-primary);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.stats-card {
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(8px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.stats-title {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: var(--secondary-color);
|
||||
text-shadow: 0 0 10px rgba(64, 224, 208, 0.3);
|
||||
}
|
||||
|
||||
/* 列表控件 */
|
||||
.list-container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(10px);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid rgba(64, 224, 208, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.list-item:active {
|
||||
background: rgba(64, 224, 208, 0.1);
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.list-item-title {
|
||||
font-size: 16px;
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.list-item-subtitle {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 4px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.list-item-value {
|
||||
font-size: 16px;
|
||||
color: var(--secondary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 历史记录列表 */
|
||||
.history-list {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
background: rgba(15, 52, 96, 0.4);
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background: rgba(64, 224, 208, 0.1);
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid var(--secondary-color);
|
||||
transition: all 0.3s ease;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.history-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.history-item.hit {
|
||||
border-left-color: var(--danger-color);
|
||||
background: rgba(255, 71, 87, 0.1);
|
||||
}
|
||||
|
||||
.history-item.miss {
|
||||
border-left-color: var(--text-tertiary);
|
||||
background: rgba(108, 117, 125, 0.1);
|
||||
}
|
||||
|
||||
.history-item.destroy {
|
||||
border-left-color: var(--accent-color);
|
||||
background: rgba(245, 158, 11, 0.2);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 网格控件 */
|
||||
.game-grid {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
background: rgba(15, 52, 96, 0.6);
|
||||
border: 2px solid rgba(64, 224, 208, 0.5);
|
||||
border-radius: 12px;
|
||||
padding: 6px;
|
||||
backdrop-filter: blur(8px);
|
||||
position: relative;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
grid-template-rows: repeat(10, 1fr);
|
||||
gap: 1px;
|
||||
background: rgba(64, 224, 208, 0.1);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.grid-cell {
|
||||
background: rgba(15, 52, 96, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
min-height: 30px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.grid-cell:active {
|
||||
background: rgba(64, 224, 208, 0.4);
|
||||
transform: scale(0.95);
|
||||
border-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.grid-cell.hit {
|
||||
background: linear-gradient(135deg, var(--danger-color) 0%, var(--danger-light) 100%);
|
||||
color: white;
|
||||
animation: hitFlash 0.6s ease-out;
|
||||
box-shadow: 0 0 15px var(--danger-color);
|
||||
}
|
||||
|
||||
.grid-cell.miss {
|
||||
background: rgba(108, 117, 125, 0.6);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
@keyframes hitFlash {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 10px var(--danger-color);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 0 20px var(--danger-color);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 5px var(--danger-color);
|
||||
}
|
||||
}
|
||||
|
||||
/* 状态指示器 */
|
||||
.network-status-indicator {
|
||||
position: fixed;
|
||||
top: calc(15px + env(safe-area-inset-top));
|
||||
right: 15px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--secondary-color);
|
||||
z-index: 101;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.network-status-indicator.offline {
|
||||
background: var(--danger-color);
|
||||
animation: networkPulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes networkPulse {
|
||||
0%, 100% { opacity: 0.8; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
|
||||
.turn-indicator {
|
||||
position: fixed;
|
||||
top: calc(70px + env(safe-area-inset-top));
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 8px 20px;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
z-index: 99;
|
||||
backdrop-filter: blur(10px);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.turn-indicator.my-turn {
|
||||
background: linear-gradient(135deg, var(--secondary-color) 0%, var(--secondary-light) 100%);
|
||||
color: #1a1a2e;
|
||||
box-shadow: 0 4px 20px rgba(64, 224, 208, 0.4);
|
||||
}
|
||||
|
||||
.turn-indicator.opponent-turn {
|
||||
background: linear-gradient(135deg, rgba(255, 71, 87, 0.9) 0%, rgba(255, 56, 56, 0.9) 100%);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 71, 87, 0.6);
|
||||
box-shadow: 0 4px 20px rgba(255, 71, 87, 0.3);
|
||||
}
|
||||
|
||||
/* 触摸反馈 */
|
||||
.haptic-feedback {
|
||||
animation: hapticVibrate 0.1s ease-out;
|
||||
}
|
||||
|
||||
@keyframes hapticVibrate {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
25% { transform: translateX(-2px); }
|
||||
75% { transform: translateX(2px); }
|
||||
}
|
||||
|
||||
/* 响应式设计增强 */
|
||||
@media (max-width: 375px) {
|
||||
.btn {
|
||||
font-size: 15px;
|
||||
min-height: 42px;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.grid-cell {
|
||||
font-size: 8px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 640px) {
|
||||
.main-content {
|
||||
justify-content: flex-start;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 10px 0;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 高对比度支持 */
|
||||
@media (prefers-contrast: high) {
|
||||
:root {
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #e5e5e5;
|
||||
--border-primary: #ffffff;
|
||||
--bg-secondary: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 减少动画偏好 */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 暗色模式强制支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
180
01_文档/原型设计/移动端控件样式示例.html
Normal file
180
01_文档/原型设计/移动端控件样式示例.html
Normal file
@@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>移动端控件样式示例</title>
|
||||
<meta name="theme-color" content="#0f1419">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<link rel="stylesheet" href="移动端控件样式示例.css">
|
||||
</head>
|
||||
<body class="safe-area">
|
||||
<div class="app-container">
|
||||
<div class="status-bar">
|
||||
<div class="network-status">
|
||||
<div class="connection-dot"></div>
|
||||
<span>在线</span>
|
||||
</div>
|
||||
<div class="app-version">v1.0.0</div>
|
||||
</div>
|
||||
|
||||
<main class="main-content">
|
||||
<h1 class="page-title">移动端控件样式示例</h1>
|
||||
|
||||
<div class="tab-container">
|
||||
<div class="tab-header">
|
||||
<div class="tab-item active" data-tab="tab1">卡片控件</div>
|
||||
<div class="tab-item" data-tab="tab2">列表控件</div>
|
||||
<div class="tab-item" data-tab="tab3">网格控件</div>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="tab1">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">基础卡片</h3>
|
||||
<span class="card-subtitle">副标题</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>这是卡片内容区域,可以放置各种信息。卡片控件是移动端应用中最常用的容器之一。</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-secondary">取消</button>
|
||||
<button class="btn btn-primary">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-card">
|
||||
<div class="stats-title">统计项</div>
|
||||
<div class="stats-value">100</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="tab2">
|
||||
<div class="list-container">
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">列表项1</div>
|
||||
<div class="list-item-subtitle">描述信息</div>
|
||||
</div>
|
||||
<div class="list-item-value">值1</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">列表项2</div>
|
||||
<div class="list-item-subtitle">描述信息</div>
|
||||
</div>
|
||||
<div class="list-item-value">值2</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">列表项3</div>
|
||||
<div class="list-item-subtitle">描述信息</div>
|
||||
</div>
|
||||
<div class="list-item-value">值3</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="history-list">
|
||||
<div class="history-item">玩家攻击 A3: 命中机翼</div>
|
||||
<div class="history-item hit">敌方攻击 B5: 命中机身</div>
|
||||
<div class="history-item miss">玩家攻击 C7: 未命中</div>
|
||||
<div class="history-item destroy">敌方攻击 D2: 击毁敌机!</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="tab3">
|
||||
<div class="game-grid">
|
||||
<div class="grid-container">
|
||||
<!-- 生成10x10网格 -->
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const gridContainer = document.querySelector('#tab3 .grid-container');
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const cell = document.createElement('div');
|
||||
cell.className = 'grid-cell';
|
||||
cell.textContent = String.fromCharCode(65 + Math.floor(i / 10)) + (i % 10 + 1);
|
||||
|
||||
// 添加一些示例状态
|
||||
if (i === 22) cell.classList.add('hit');
|
||||
if (i === 45) cell.classList.add('miss');
|
||||
if (i === 67) cell.classList.add('hit');
|
||||
|
||||
gridContainer.appendChild(cell);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-primary">主要操作</button>
|
||||
<button class="btn btn-success">成功操作</button>
|
||||
<button class="btn btn-secondary">次要操作</button>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 动态星空背景 -->
|
||||
<div class="star-field" id="starField"></div>
|
||||
|
||||
<!-- 网络状态指示器 -->
|
||||
<div class="network-status-indicator"></div>
|
||||
|
||||
<!-- 回合指示器 -->
|
||||
<div class="turn-indicator my-turn">我的回合</div>
|
||||
|
||||
<script>
|
||||
// 页签切换功能
|
||||
document.querySelectorAll('.tab-item').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
const tabId = tab.dataset.tab;
|
||||
|
||||
// 更新标签状态
|
||||
document.querySelectorAll('.tab-item').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
|
||||
// 更新内容显示
|
||||
document.querySelectorAll('.tab-pane').forEach(pane => pane.classList.remove('active'));
|
||||
document.getElementById(tabId).classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// 触觉反馈
|
||||
document.querySelectorAll('.btn, .list-item, .tab-item').forEach(element => {
|
||||
element.addEventListener('click', () => {
|
||||
if ('vibrate' in navigator) {
|
||||
navigator.vibrate(10);
|
||||
}
|
||||
document.body.classList.add('haptic-feedback');
|
||||
setTimeout(() => document.body.classList.remove('haptic-feedback'), 100);
|
||||
});
|
||||
});
|
||||
|
||||
// 创建动态星空背景
|
||||
function createStarField() {
|
||||
const starField = document.getElementById('starField');
|
||||
const numStars = 50;
|
||||
|
||||
for (let i = 0; i < numStars; i++) {
|
||||
const star = document.createElement('div');
|
||||
star.className = 'star';
|
||||
star.style.width = Math.random() * 3 + 'px';
|
||||
star.style.height = star.style.width;
|
||||
star.style.left = Math.random() * 100 + '%';
|
||||
star.style.top = Math.random() * 100 + '%';
|
||||
star.style.animationDelay = Math.random() * 3 + 's';
|
||||
starField.appendChild(star);
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
createStarField();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
963
01_文档/原型设计/移动端控件样式设计规范.md
Normal file
963
01_文档/原型设计/移动端控件样式设计规范.md
Normal file
@@ -0,0 +1,963 @@
|
||||
# 移动端控件样式设计规范
|
||||
|
||||
## 1. 设计理念
|
||||
|
||||
### 1.1 核心原则
|
||||
- **移动优先**:专为手机端设计,确保在小屏幕上的最佳体验
|
||||
- **避免滚动**:页面内容尽量在一屏内展示,过长内容使用页签切换
|
||||
- **深色主题**:采用深色背景,减少视觉疲劳,增强科技感
|
||||
- **高对比度**:确保文字和控件在各种环境下清晰可见
|
||||
|
||||
### 1.2 视觉风格
|
||||
- **科技感**:使用渐变色彩和毛玻璃效果,营造现代科技氛围
|
||||
- **简洁明了**:控件设计简洁,功能明确,避免复杂装饰
|
||||
- **一致性**:所有页面和控件保持统一的设计语言
|
||||
|
||||
## 2. 色彩系统
|
||||
|
||||
### 2.1 主色调
|
||||
```css
|
||||
:root {
|
||||
/* 主色调 - 深空科技蓝 */
|
||||
--primary-color: #6366f1;
|
||||
--primary-light: #8b5cf6;
|
||||
--primary-dark: #4f46e5;
|
||||
|
||||
/* 辅助色 - 科技青色 */
|
||||
--secondary-color: #40e0d0;
|
||||
--secondary-light: #26d0ce;
|
||||
|
||||
/* 强调色 - 橙色 */
|
||||
--accent-color: #f59e0b;
|
||||
--accent-light: #fbbf24;
|
||||
|
||||
/* 危险色 - 红色 */
|
||||
--danger-color: #ff4757;
|
||||
--danger-light: #ff6b6b;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 背景色系
|
||||
```css
|
||||
:root {
|
||||
/* 背景色系 - 深色渐变 */
|
||||
--bg-primary: #0f1419;
|
||||
--bg-secondary: #1a1d29;
|
||||
--bg-tertiary: #252837;
|
||||
--bg-elevated: #2d3142;
|
||||
|
||||
/* 渐变背景 */
|
||||
--gradient-bg: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 30%, #16213e 70%, #0f3460 100%);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 边框色系
|
||||
```css
|
||||
:root {
|
||||
/* 边框色系 */
|
||||
--border-primary: #3d4159;
|
||||
--border-secondary: #4a5073;
|
||||
--border-highlight: #6366f1;
|
||||
--border-accent: rgba(64, 224, 208, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 文字色系
|
||||
```css
|
||||
:root {
|
||||
/* 文字色系 */
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #b4b7c9;
|
||||
--text-tertiary: #9ca3af;
|
||||
--text-disabled: #6b7280;
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 布局原则
|
||||
|
||||
### 3.1 安全区域适配
|
||||
```css
|
||||
.safe-area {
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 触摸目标尺寸
|
||||
```css
|
||||
:root {
|
||||
--touch-target-min: 44px;
|
||||
--safe-area-padding: 20px;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 页签切换设计
|
||||
当内容过长时,使用页签切换替代滚动:
|
||||
|
||||
```html
|
||||
<div class="tab-container">
|
||||
<div class="tab-header">
|
||||
<div class="tab-item active" data-tab="tab1">标签1</div>
|
||||
<div class="tab-item" data-tab="tab2">标签2</div>
|
||||
<div class="tab-item" data-tab="tab3">标签3</div>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="tab1">内容1</div>
|
||||
<div class="tab-pane" id="tab2">内容2</div>
|
||||
<div class="tab-pane" id="tab3">内容3</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tab-container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
display: flex;
|
||||
background: var(--bg-tertiary);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
color: var(--primary-color);
|
||||
background: var(--bg-secondary);
|
||||
border-bottom: 2px solid var(--primary-color);
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding: 20px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-pane.active {
|
||||
display: block;
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## 4. 控件样式规范
|
||||
|
||||
### 4.1 按钮控件
|
||||
|
||||
#### 4.1.1 主要按钮
|
||||
```css
|
||||
.btn-primary {
|
||||
min-height: var(--touch-target-min);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 14px 24px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
|
||||
color: #ffffff;
|
||||
box-shadow: 0 4px 16px rgba(99, 102, 241, 0.3);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.btn-primary:hover, .btn-primary:focus {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.4);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 8px rgba(99, 102, 241, 0.4);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.1.2 成功按钮
|
||||
```css
|
||||
.btn-success {
|
||||
min-height: var(--touch-target-min);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 14px 24px;
|
||||
background: linear-gradient(135deg, var(--secondary-color), var(--secondary-light));
|
||||
color: #1a1a2e;
|
||||
box-shadow: 0 4px 16px rgba(64, 224, 208, 0.3);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.btn-success:hover, .btn-success:focus {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(64, 224, 208, 0.4);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.1.3 次要按钮
|
||||
```css
|
||||
.btn-secondary {
|
||||
min-height: var(--touch-target-min);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
padding: 14px 24px;
|
||||
background: rgba(99, 102, 241, 0.15);
|
||||
color: var(--primary-color);
|
||||
border: 1px solid var(--primary-color);
|
||||
backdrop-filter: blur(10px);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.btn-secondary:hover, .btn-secondary:focus {
|
||||
background: rgba(99, 102, 241, 0.25);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 卡片控件
|
||||
|
||||
#### 4.2.1 基础卡片
|
||||
```css
|
||||
.card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
margin-top: 16px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--border-primary);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2.2 统计卡片
|
||||
```css
|
||||
.stats-card {
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(8px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.stats-title {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: var(--secondary-color);
|
||||
text-shadow: 0 0 10px rgba(64, 224, 208, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 列表控件
|
||||
|
||||
#### 4.3.1 基础列表
|
||||
```css
|
||||
.list-container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: rgba(22, 33, 62, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.3);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.list-item {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid rgba(64, 224, 208, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.list-item:active {
|
||||
background: rgba(64, 224, 208, 0.1);
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.list-item-title {
|
||||
font-size: 16px;
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.list-item-subtitle {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.list-item-value {
|
||||
font-size: 16px;
|
||||
color: var(--secondary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.3.2 历史记录列表
|
||||
```css
|
||||
.history-list {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
background: rgba(15, 52, 96, 0.4);
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background: rgba(64, 224, 208, 0.1);
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid var(--secondary-color);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.history-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.history-item.hit {
|
||||
border-left-color: var(--danger-color);
|
||||
background: rgba(255, 71, 87, 0.1);
|
||||
}
|
||||
|
||||
.history-item.miss {
|
||||
border-left-color: var(--text-tertiary);
|
||||
background: rgba(108, 117, 125, 0.1);
|
||||
}
|
||||
|
||||
.history-item.destroy {
|
||||
border-left-color: var(--accent-color);
|
||||
background: rgba(245, 158, 11, 0.2);
|
||||
font-weight: 600;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 网格控件
|
||||
|
||||
#### 4.4.1 游戏网格
|
||||
```css
|
||||
.game-grid {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
background: rgba(15, 52, 96, 0.6);
|
||||
border: 2px solid rgba(64, 224, 208, 0.5);
|
||||
border-radius: 12px;
|
||||
padding: 6px;
|
||||
backdrop-filter: blur(8px);
|
||||
position: relative;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
grid-template-rows: repeat(10, 1fr);
|
||||
gap: 1px;
|
||||
background: rgba(64, 224, 208, 0.1);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.grid-cell {
|
||||
background: rgba(15, 52, 96, 0.8);
|
||||
border: 1px solid rgba(64, 224, 208, 0.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
min-height: 30px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.grid-cell:active {
|
||||
background: rgba(64, 224, 208, 0.4);
|
||||
transform: scale(0.95);
|
||||
border-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.grid-cell.hit {
|
||||
background: linear-gradient(135deg, var(--danger-color) 0%, var(--danger-light) 100%);
|
||||
color: white;
|
||||
animation: hitFlash 0.6s ease-out;
|
||||
box-shadow: 0 0 15px var(--danger-color);
|
||||
}
|
||||
|
||||
.grid-cell.miss {
|
||||
background: rgba(108, 117, 125, 0.6);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
@keyframes hitFlash {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 10px var(--danger-color);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 0 20px var(--danger-color);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 5px var(--danger-color);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 状态指示器
|
||||
|
||||
#### 4.5.1 网络状态
|
||||
```css
|
||||
.network-status {
|
||||
position: fixed;
|
||||
top: calc(15px + env(safe-area-inset-top));
|
||||
right: 15px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--secondary-color);
|
||||
z-index: 101;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.network-status.offline {
|
||||
background: var(--danger-color);
|
||||
animation: networkPulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes networkPulse {
|
||||
0%, 100% { opacity: 0.8; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.5.2 回合指示器
|
||||
```css
|
||||
.turn-indicator {
|
||||
position: fixed;
|
||||
top: calc(70px + env(safe-area-inset-top));
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 8px 20px;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
z-index: 99;
|
||||
backdrop-filter: blur(10px);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.turn-indicator.my-turn {
|
||||
background: linear-gradient(135deg, var(--secondary-color) 0%, var(--secondary-light) 100%);
|
||||
color: #1a1a2e;
|
||||
box-shadow: 0 4px 20px rgba(64, 224, 208, 0.4);
|
||||
}
|
||||
|
||||
.turn-indicator.opponent-turn {
|
||||
background: linear-gradient(135deg, rgba(255, 71, 87, 0.9) 0%, rgba(255, 56, 56, 0.9) 100%);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 71, 87, 0.6);
|
||||
box-shadow: 0 4px 20px rgba(255, 71, 87, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 动画效果
|
||||
|
||||
### 5.1 背景动画
|
||||
```css
|
||||
/* 动态星空背景 */
|
||||
.star-field {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.star {
|
||||
position: absolute;
|
||||
background: rgba(64, 224, 208, 0.8);
|
||||
border-radius: 50%;
|
||||
animation: twinkle 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 0.3; transform: scale(1); }
|
||||
50% { opacity: 1; transform: scale(1.2); }
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 按钮触摸反馈
|
||||
```css
|
||||
.btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.3s, height 0.3s;
|
||||
}
|
||||
|
||||
.btn:active::before {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 页面切换动画
|
||||
```css
|
||||
.page-transition-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.page-transition-enter-active {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
.page-transition-exit {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.page-transition-exit-active {
|
||||
opacity: 0;
|
||||
transform: translateX(-100%);
|
||||
transition: all 0.3s ease-in;
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 移动端适配
|
||||
|
||||
### 6.1 响应式断点
|
||||
```css
|
||||
/* 小屏幕手机 */
|
||||
@media (max-width: 375px) {
|
||||
.btn {
|
||||
font-size: 15px;
|
||||
min-height: 42px;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.grid-cell {
|
||||
font-size: 8px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 短屏幕手机 */
|
||||
@media (max-height: 640px) {
|
||||
.main-content {
|
||||
justify-content: flex-start;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.game-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 15px 0;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 横屏模式 */
|
||||
@media (orientation: landscape) and (max-height: 500px) {
|
||||
.game-container {
|
||||
top: calc(70px + env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.turn-indicator {
|
||||
top: calc(40px + env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.boards-container {
|
||||
flex-direction: row;
|
||||
max-width: 90%;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.board-section {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 触摸优化
|
||||
```css
|
||||
/* 防止双指缩放和滚动 */
|
||||
body {
|
||||
touch-action: manipulation;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* 触摸反馈 */
|
||||
.haptic-feedback {
|
||||
animation: hapticVibrate 0.1s ease-out;
|
||||
}
|
||||
|
||||
@keyframes hapticVibrate {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
25% { transform: translateX(-2px); }
|
||||
75% { transform: translateX(2px); }
|
||||
}
|
||||
|
||||
/* 防止长按菜单 */
|
||||
* {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 无障碍支持
|
||||
```css
|
||||
/* 高对比度支持 */
|
||||
@media (prefers-contrast: high) {
|
||||
:root {
|
||||
--text-primary: #ffffff;
|
||||
--text-secondary: #e5e5e5;
|
||||
--border-primary: #ffffff;
|
||||
--bg-secondary: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
/* 减少动画偏好 */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 暗色模式强制支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 实现示例
|
||||
|
||||
### 7.1 完整页面示例
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>移动端页面示例</title>
|
||||
<style>
|
||||
/* 引入上述所有CSS变量和基础样式 */
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Microsoft YaHei UI", sans-serif;
|
||||
background: var(--gradient-bg);
|
||||
color: var(--text-primary);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--safe-area-padding);
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background: rgba(26, 29, 41, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
padding: 8px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tab-container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="safe-area">
|
||||
<div class="app-container">
|
||||
<div class="status-bar">
|
||||
<div class="network-status">
|
||||
<div class="connection-dot"></div>
|
||||
<span>在线</span>
|
||||
</div>
|
||||
<div class="app-version">v1.0.0</div>
|
||||
</div>
|
||||
|
||||
<main class="main-content">
|
||||
<h1 class="page-title">页面标题</h1>
|
||||
|
||||
<div class="tab-container">
|
||||
<div class="tab-header">
|
||||
<div class="tab-item active" data-tab="tab1">标签1</div>
|
||||
<div class="tab-item" data-tab="tab2">标签2</div>
|
||||
<div class="tab-item" data-tab="tab3">标签3</div>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="tab1">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">卡片标题</h3>
|
||||
<span class="card-subtitle">副标题</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>这是卡片内容区域,可以放置各种信息。</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-secondary">取消</button>
|
||||
<button class="btn btn-primary">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="tab2">
|
||||
<div class="stats-card">
|
||||
<div class="stats-title">统计项</div>
|
||||
<div class="stats-value">100</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="tab3">
|
||||
<div class="list-container">
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">列表项1</div>
|
||||
<div class="list-item-subtitle">描述信息</div>
|
||||
</div>
|
||||
<div class="list-item-value">值1</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">列表项2</div>
|
||||
<div class="list-item-subtitle">描述信息</div>
|
||||
</div>
|
||||
<div class="list-item-value">值2</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-primary">主要操作</button>
|
||||
<button class="btn btn-secondary">次要操作</button>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 页签切换功能
|
||||
document.querySelectorAll('.tab-item').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
const tabId = tab.dataset.tab;
|
||||
|
||||
// 更新标签状态
|
||||
document.querySelectorAll('.tab-item').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
|
||||
// 更新内容显示
|
||||
document.querySelectorAll('.tab-pane').forEach(pane => pane.classList.remove('active'));
|
||||
document.getElementById(tabId).classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// 触觉反馈
|
||||
document.querySelectorAll('.btn, .list-item, .tab-item').forEach(element => {
|
||||
element.addEventListener('click', () => {
|
||||
if ('vibrate' in navigator) {
|
||||
navigator.vibrate(10);
|
||||
}
|
||||
document.body.classList.add('haptic-feedback');
|
||||
setTimeout(() => document.body.classList.remove('haptic-feedback'), 100);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## 8. 微信小程序适配建议
|
||||
|
||||
### 8.1 样式转换
|
||||
- 将CSS变量转换为微信小程序的theme.json或全局样式
|
||||
- 使用rpx单位替代px,确保在不同屏幕尺寸下的适配
|
||||
- 将backdrop-filter等不支持的效果替换为半透明背景
|
||||
|
||||
### 8.2 组件转换
|
||||
- 将HTML控件转换为微信小程序的自定义组件
|
||||
- 使用微信小程序的动画API替代CSS动画
|
||||
- 利用微信小程序的页面生命周期管理状态
|
||||
|
||||
### 8.3 性能优化
|
||||
- 使用微信小程序的虚拟列表处理长列表
|
||||
- 优化图片资源,使用微信小程序的图片压缩
|
||||
- 合理使用setData,避免频繁更新页面数据
|
||||
|
||||
## 9. 总结
|
||||
|
||||
本设计规范基于提供的两个HTML文件的设计风格,总结了一套适用于手机端微信小程序的控件样式设计规范。主要特点包括:
|
||||
|
||||
1. **深色科技主题**:使用深色背景和渐变色彩,营造现代科技感
|
||||
2. **移动优先**:专为手机端设计,考虑触摸操作和屏幕尺寸限制
|
||||
3. **避免滚动**:通过页签切换等方式减少页面滚动
|
||||
4. **统一视觉语言**:所有控件保持一致的设计风格
|
||||
5. **丰富的交互反馈**:提供视觉、触觉等多种反馈方式
|
||||
6. **良好的无障碍支持**:考虑高对比度、减少动画等特殊需求
|
||||
|
||||
通过遵循本设计规范,可以创建出用户体验良好、视觉一致的移动端应用界面。
|
||||
Reference in New Issue
Block a user