把大致框架搭好1

This commit is contained in:
2025-09-02 08:40:37 +08:00
parent 56659d9790
commit b139fb14d9
108 changed files with 25897 additions and 3 deletions

View File

@@ -0,0 +1,167 @@
/* 背景样式文件 - 金色光辉主题 */
/* 主背景 */
body {
background: linear-gradient(
135deg,
#fff8dc 0%,
#ffeaa7 25%,
#fdcb6e 50%,
#e17055 75%,
#d63031 100%
);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
position: relative;
}
/* 背景装饰层 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 20% 80%, rgba(255, 215, 0, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 223, 0, 0.1) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(212, 175, 55, 0.05) 0%, transparent 50%);
pointer-events: none;
z-index: 1;
}
/* 动态光点效果 */
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(2px 2px at 20px 30px, rgba(255, 215, 0, 0.3), transparent),
radial-gradient(2px 2px at 40px 70px, rgba(255, 223, 0, 0.2), transparent),
radial-gradient(1px 1px at 90px 40px, rgba(212, 175, 55, 0.4), transparent),
radial-gradient(1px 1px at 130px 80px, rgba(255, 215, 0, 0.2), transparent),
radial-gradient(2px 2px at 160px 30px, rgba(255, 223, 0, 0.3), transparent);
background-repeat: repeat;
background-size: 200px 100px;
animation: sparkle 20s linear infinite;
pointer-events: none;
z-index: 2;
}
/* 背景动画 */
@keyframes gradientShift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@keyframes sparkle {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(-100vh);
opacity: 0;
}
}
/* 响应式背景调整 */
/* 平板端背景 */
@media (min-width: 768px) and (max-width: 1024px) {
body::after {
background-size: 250px 120px;
}
}
/* 电脑端背景 */
@media (min-width: 1024px) {
body {
background-size: 300% 300%;
}
body::after {
background-size: 300px 150px;
animation-duration: 25s;
}
}
/* 手机端背景优化 */
@media (max-width: 767px) {
body {
background-size: 200% 200%;
animation-duration: 10s;
}
body::before {
background:
radial-gradient(circle at 30% 70%, rgba(255, 215, 0, 0.08) 0%, transparent 40%),
radial-gradient(circle at 70% 30%, rgba(255, 223, 0, 0.08) 0%, transparent 40%);
}
body::after {
background-size: 150px 80px;
animation-duration: 15s;
}
}
/* 超小屏幕背景 */
@media (max-width: 479px) {
body {
background: linear-gradient(
135deg,
#fff8dc 0%,
#ffeaa7 50%,
#fdcb6e 100%
);
background-size: 150% 150%;
}
body::after {
background-size: 120px 60px;
}
}
/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
body {
background: linear-gradient(
135deg,
#2c1810 0%,
#3d2914 25%,
#4a3319 50%,
#5c3e1f 75%,
#6b4423 100%
);
}
body::before {
background:
radial-gradient(circle at 20% 80%, rgba(255, 215, 0, 0.05) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 223, 0, 0.05) 0%, transparent 50%);
}
}
/* 减少动画效果(用户偏好) */
@media (prefers-reduced-motion: reduce) {
body,
body::before,
body::after {
animation: none;
}
body {
background: linear-gradient(135deg, #fff8dc 0%, #ffeaa7 50%, #fdcb6e 100%);
}
}

View File

@@ -0,0 +1,357 @@
/* 基础样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #2c1810;
overflow-x: hidden;
}
/* 容器布局 */
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
position: relative;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 40px;
z-index: 10;
}
.title {
font-size: 3rem;
font-weight: 700;
color: #d4af37;
text-shadow:
0 0 10px rgba(212, 175, 55, 0.8),
0 0 20px rgba(212, 175, 55, 0.6),
0 0 30px rgba(212, 175, 55, 0.4);
margin-bottom: 10px;
animation: titleGlow 3s ease-in-out infinite alternate;
}
.subtitle {
font-size: 1.2rem;
color: #b8860b;
opacity: 0.9;
text-shadow: 0 0 5px rgba(184, 134, 11, 0.5);
}
/* 主内容区域 */
.main-content {
width: 100%;
max-width: 800px;
z-index: 10;
}
/* 一言容器 */
.quote-container {
background: linear-gradient(135deg, rgba(255, 215, 0, 0.1), rgba(255, 223, 0, 0.05));
border: 2px solid rgba(212, 175, 55, 0.3);
border-radius: 20px;
padding: 40px;
margin-bottom: 30px;
backdrop-filter: blur(10px);
box-shadow:
0 8px 32px rgba(212, 175, 55, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
position: relative;
overflow: hidden;
}
.quote-container::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #ffd700, #ffed4e, #ffd700, #ffed4e);
border-radius: 22px;
z-index: -1;
animation: borderGlow 4s linear infinite;
}
/* 加载状态 */
.loading {
display: none;
text-align: center;
color: #d4af37;
}
.loading.show {
display: block;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(212, 175, 55, 0.3);
border-top: 4px solid #d4af37;
border-radius: 50%;
margin: 0 auto 15px;
animation: spin 1s linear infinite;
}
/* 一言显示 */
.quote-display {
display: block;
text-align: center;
}
.quote-display.hide {
display: none;
}
.quote-text {
font-size: 1.8rem;
line-height: 1.8;
color: #2c1810;
margin-bottom: 20px;
text-shadow: 0 1px 2px rgba(212, 175, 55, 0.1);
font-weight: 500;
}
.quote-index {
font-size: 0.9rem;
color: #b8860b;
opacity: 0.8;
}
/* 错误信息 */
.error-message {
display: none;
text-align: center;
color: #cd853f;
}
.error-message.show {
display: block;
}
.error-icon {
font-size: 2rem;
margin-bottom: 10px;
}
.error-text {
font-size: 1.1rem;
line-height: 1.5;
}
/* 控制按钮 */
.controls {
text-align: center;
}
.refresh-btn {
background: linear-gradient(135deg, #ffd700, #ffed4e);
border: none;
border-radius: 50px;
padding: 15px 30px;
font-size: 1.1rem;
font-weight: 600;
color: #2c1810;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 10px;
transition: all 0.3s ease;
box-shadow:
0 4px 15px rgba(212, 175, 55, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
position: relative;
overflow: hidden;
}
.refresh-btn:hover {
transform: translateY(-2px);
box-shadow:
0 6px 20px rgba(212, 175, 55, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.refresh-btn:active {
transform: translateY(0);
}
.refresh-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.btn-icon {
font-size: 1.2rem;
transition: transform 0.3s ease;
}
.refresh-btn:hover .btn-icon {
transform: rotate(180deg);
}
/* 底部 */
.footer {
margin-top: 40px;
text-align: center;
color: #b8860b;
opacity: 0.8;
font-size: 0.9rem;
}
/* 动画效果 */
@keyframes titleGlow {
0% {
text-shadow:
0 0 10px rgba(212, 175, 55, 0.8),
0 0 20px rgba(212, 175, 55, 0.6),
0 0 30px rgba(212, 175, 55, 0.4);
}
100% {
text-shadow:
0 0 15px rgba(212, 175, 55, 1),
0 0 25px rgba(212, 175, 55, 0.8),
0 0 35px rgba(212, 175, 55, 0.6);
}
}
@keyframes borderGlow {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 平板端适配 (768px - 1024px) */
@media (min-width: 768px) and (max-width: 1024px) {
.container {
padding: 30px;
}
.title {
font-size: 3.5rem;
}
.subtitle {
font-size: 1.3rem;
}
.quote-container {
padding: 50px;
}
.quote-text {
font-size: 2rem;
}
}
/* 电脑端适配 (1024px+) */
@media (min-width: 1024px) {
.container {
padding: 40px;
}
.title {
font-size: 4rem;
}
.subtitle {
font-size: 1.4rem;
}
.quote-container {
padding: 60px;
max-width: 900px;
}
.quote-text {
font-size: 2.2rem;
line-height: 1.9;
}
.refresh-btn {
padding: 18px 36px;
font-size: 1.2rem;
}
}
/* 手机端适配 (小于768px) */
@media (max-width: 767px) {
.container {
padding: 15px;
}
.header {
margin-bottom: 30px;
}
.title {
font-size: 2.5rem;
}
.subtitle {
font-size: 1rem;
}
.quote-container {
padding: 25px;
border-radius: 15px;
}
.quote-text {
font-size: 1.4rem;
line-height: 1.6;
}
.refresh-btn {
padding: 12px 24px;
font-size: 1rem;
}
.footer {
margin-top: 30px;
font-size: 0.8rem;
}
}
/* 超小屏幕适配 (小于480px) */
@media (max-width: 479px) {
.title {
font-size: 2rem;
}
.quote-container {
padding: 20px;
}
.quote-text {
font-size: 1.2rem;
}
.refresh-btn {
padding: 10px 20px;
font-size: 0.9rem;
}
}

View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>随机一言 - 金色光辉</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/background.css">
</head>
<body>
<div class="container">
<header class="header">
<h1 class="title">随机一言</h1>
<p class="subtitle">每一句话都是心灵的光芒</p>
</header>
<main class="main-content">
<div class="quote-container">
<div class="loading" id="loading">
<div class="loading-spinner"></div>
<p>正在获取一言...</p>
</div>
<div class="quote-display" id="quoteDisplay">
<div class="quote-text" id="quoteText">
点击下方按钮获取一言
</div>
<div class="quote-index" id="quoteIndex"></div>
</div>
<div class="error-message" id="errorMessage">
<div class="error-icon">⚠️</div>
<div class="error-text" id="errorText"></div>
</div>
</div>
<div class="controls">
<button class="refresh-btn" id="refreshBtn">
<span class="btn-icon">🔄</span>
<span class="btn-text">获取新一言</span>
</button>
</div>
</main>
<footer class="footer">
<p>愿每一句话都能温暖你的心</p>
</footer>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -0,0 +1,225 @@
// 随机一言 JavaScript 功能实现
class HitokotoApp {
constructor() {
// API接口列表
this.apiEndpoints = [
"https://60s-cf.viki.moe",
"https://60s.viki.moe",
"https://60s.b23.run",
"https://60s.114128.xyz",
"https://60s-cf.114128.xyz"
];
this.currentEndpointIndex = 0;
this.isLoading = false;
// DOM 元素
this.elements = {
loading: document.getElementById('loading'),
quoteDisplay: document.getElementById('quoteDisplay'),
quoteText: document.getElementById('quoteText'),
quoteIndex: document.getElementById('quoteIndex'),
errorMessage: document.getElementById('errorMessage'),
errorText: document.getElementById('errorText'),
refreshBtn: document.getElementById('refreshBtn')
};
this.init();
}
// 初始化应用
init() {
this.bindEvents();
this.hideAllStates();
this.showQuoteDisplay();
}
// 绑定事件
bindEvents() {
this.elements.refreshBtn.addEventListener('click', () => {
this.fetchHitokoto();
});
// 键盘快捷键支持
document.addEventListener('keydown', (e) => {
if (e.code === 'Space' && !this.isLoading) {
e.preventDefault();
this.fetchHitokoto();
}
});
}
// 隐藏所有状态
hideAllStates() {
this.elements.loading.classList.remove('show');
this.elements.quoteDisplay.classList.remove('hide');
this.elements.errorMessage.classList.remove('show');
}
// 显示加载状态
showLoading() {
this.hideAllStates();
this.elements.loading.classList.add('show');
this.elements.quoteDisplay.classList.add('hide');
this.elements.refreshBtn.disabled = true;
this.isLoading = true;
}
// 显示一言内容
showQuoteDisplay() {
this.hideAllStates();
this.elements.quoteDisplay.classList.remove('hide');
this.elements.refreshBtn.disabled = false;
this.isLoading = false;
}
// 显示错误信息
showError(message) {
this.hideAllStates();
this.elements.errorMessage.classList.add('show');
this.elements.errorText.textContent = message;
this.elements.refreshBtn.disabled = false;
this.isLoading = false;
}
// 获取一言数据
async fetchHitokoto() {
if (this.isLoading) return;
this.showLoading();
// 尝试所有API接口
for (let i = 0; i < this.apiEndpoints.length; i++) {
const endpointIndex = (this.currentEndpointIndex + i) % this.apiEndpoints.length;
const endpoint = this.apiEndpoints[endpointIndex];
try {
const result = await this.tryFetchFromEndpoint(endpoint);
if (result.success) {
this.currentEndpointIndex = endpointIndex;
this.displayHitokoto(result.data);
return;
}
} catch (error) {
console.warn(`接口 ${endpoint} 请求失败:`, error.message);
continue;
}
}
// 所有接口都失败
this.showError('所有接口都无法访问,请检查网络连接或稍后重试');
}
// 尝试从指定接口获取数据
async tryFetchFromEndpoint(endpoint) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
try {
const response = await fetch(`${endpoint}/v2/hitokoto?encoding=text`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
// 验证返回数据格式
if (data.code === 200 && data.data && data.data.hitokoto) {
return {
success: true,
data: data.data
};
} else {
throw new Error('返回数据格式不正确');
}
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('请求超时');
}
throw error;
}
}
// 显示一言内容
displayHitokoto(data) {
// 更新一言文本
this.elements.quoteText.textContent = data.hitokoto;
// 更新序号信息
if (data.index) {
this.elements.quoteIndex.textContent = `${data.index}`;
} else {
this.elements.quoteIndex.textContent = '';
}
// 添加淡入动画效果
this.elements.quoteText.style.opacity = '0';
this.elements.quoteIndex.style.opacity = '0';
setTimeout(() => {
this.elements.quoteText.style.transition = 'opacity 0.5s ease';
this.elements.quoteIndex.style.transition = 'opacity 0.5s ease';
this.elements.quoteText.style.opacity = '1';
this.elements.quoteIndex.style.opacity = '1';
}, 100);
this.showQuoteDisplay();
// 控制台输出调试信息
console.log('一言获取成功:', {
content: data.hitokoto,
index: data.index,
endpoint: this.apiEndpoints[this.currentEndpointIndex]
});
}
// 获取随机接口(用于负载均衡)
getRandomEndpoint() {
const randomIndex = Math.floor(Math.random() * this.apiEndpoints.length);
return this.apiEndpoints[randomIndex];
}
}
// 页面加载完成后初始化应用
document.addEventListener('DOMContentLoaded', () => {
const app = new HitokotoApp();
// 添加全局错误处理
window.addEventListener('error', (event) => {
console.error('页面发生错误:', event.error);
});
window.addEventListener('unhandledrejection', (event) => {
console.error('未处理的Promise拒绝:', event.reason);
});
// 页面可见性变化时的处理
document.addEventListener('visibilitychange', () => {
if (!document.hidden && !app.isLoading) {
// 页面重新可见时,可以选择刷新内容
console.log('页面重新可见');
}
});
console.log('随机一言应用初始化完成');
});
// 导出应用类(如果需要在其他地方使用)
if (typeof module !== 'undefined' && module.exports) {
module.exports = HitokotoApp;
}

View File

@@ -0,0 +1,7 @@
[
"https://60s-cf.viki.moe",
"https://60s.viki.moe",
"https://60s.b23.run",
"https://60s.114128.xyz",
"https://60s-cf.114128.xyz"
]

View File

@@ -0,0 +1,8 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"index": 2862,
"hitokoto": "你带上罪恶之冠,即使背负上所有罪恶和孤独,绝不让你受伤"
}
}