mirror of
https://github.com/Moe-Sakura/frontend.git
synced 2026-05-16 21:26:46 +08:00
feat: 增加背景层转场动画与暗色模式样式优化
* 在 `index.html` 中添加多种背景层转场动画效果,提升视觉体验。 * 更新 `App.vue` 中的图片切换逻辑,支持随机转场动画和慢慢放大效果。 * 增强暗色模式下的输入框和通知样式,确保视觉一致性与可读性。
This commit is contained in:
172
index.html
172
index.html
@@ -214,10 +214,140 @@
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
z-index: -2;
|
||||
/* 平滑过渡,避免闪白屏 */
|
||||
transition: background-image 1.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
/* 默认淡入淡出过渡 */
|
||||
transition: opacity 1.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
/* 持续的慢慢放大动画 */
|
||||
animation: slowZoom 10s ease-out forwards;
|
||||
}
|
||||
|
||||
/* 持续慢慢放大动画 */
|
||||
@keyframes slowZoom {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 转场动画类 */
|
||||
#background-layer.transition-fade {
|
||||
animation: fadeTransition 1.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
#background-layer.transition-zoom {
|
||||
animation: zoomTransition 1.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
#background-layer.transition-slide-left {
|
||||
animation: slideLeftTransition 1.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
#background-layer.transition-slide-right {
|
||||
animation: slideRightTransition 1.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
#background-layer.transition-blur {
|
||||
animation: blurTransition 1.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
#background-layer.transition-rotate {
|
||||
animation: rotateTransition 1.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* 淡入淡出动画 */
|
||||
@keyframes fadeTransition {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 缩放动画 */
|
||||
@keyframes zoomTransition {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 左滑动画 */
|
||||
@keyframes slideLeftTransition {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 右滑动画 */
|
||||
@keyframes slideRightTransition {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 模糊动画 */
|
||||
@keyframes blurTransition {
|
||||
0% {
|
||||
opacity: 1;
|
||||
filter: blur(0px);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.3;
|
||||
filter: blur(10px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
filter: blur(0px);
|
||||
}
|
||||
}
|
||||
|
||||
/* 旋转动画 */
|
||||
@keyframes rotateTransition {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scale(1) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) rotate(5deg);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1) rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 默认背景纹理 - 白天模式 */
|
||||
#background-layer::before {
|
||||
content: "";
|
||||
@@ -262,6 +392,44 @@
|
||||
background: rgba(15, 23, 42, 0.4);
|
||||
}
|
||||
|
||||
/* 暗色模式强制样式 */
|
||||
.dark input[type="search"],
|
||||
.dark input[type="url"],
|
||||
.dark input[type="text"],
|
||||
.dark textarea {
|
||||
background-color: rgba(30, 41, 59, 0.95) !important;
|
||||
color: rgb(226, 232, 240) !important;
|
||||
border-color: rgba(71, 85, 105, 0.5) !important;
|
||||
}
|
||||
|
||||
.dark input::placeholder,
|
||||
.dark textarea::placeholder {
|
||||
color: rgba(148, 163, 184, 0.7) !important;
|
||||
}
|
||||
|
||||
.dark input:focus,
|
||||
.dark textarea:focus {
|
||||
border-color: rgb(139, 92, 246) !important;
|
||||
}
|
||||
|
||||
/* 暗色模式下的卡片和容器 */
|
||||
.dark .usage-notice {
|
||||
background-color: rgba(30, 41, 59, 0.9) !important;
|
||||
color: rgb(203, 213, 225) !important;
|
||||
}
|
||||
|
||||
.dark .usage-notice h2 {
|
||||
color: rgb(226, 232, 240) !important;
|
||||
}
|
||||
|
||||
.dark .usage-notice strong {
|
||||
color: rgb(226, 232, 240) !important;
|
||||
}
|
||||
|
||||
.dark .usage-notice a {
|
||||
color: rgb(147, 197, 253) !important;
|
||||
}
|
||||
|
||||
/* 加载动画 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
|
||||
54
src/App.vue
54
src/App.vue
@@ -40,8 +40,8 @@ let displayInterval: number | null = null;
|
||||
|
||||
const MAX_CACHE_SIZE = 10000; // 最大缓存 10000 张图片
|
||||
const CLEANUP_BATCH_SIZE = 2000; // 每次清理 2000 张
|
||||
const FETCH_INTERVAL = 3000; // 3秒获取一次
|
||||
const DISPLAY_INTERVAL = 5000; // 5秒切换一次
|
||||
const FETCH_INTERVAL = 5000; // 5秒获取一次
|
||||
const DISPLAY_INTERVAL = 10000; // 10秒切换一次
|
||||
|
||||
const hasBackgroundImage = computed(
|
||||
() => !!randomImageUrl.value
|
||||
@@ -202,6 +202,48 @@ async function fetchAndCacheImage() {
|
||||
}
|
||||
}
|
||||
|
||||
// 转场动画类型
|
||||
const transitionTypes = [
|
||||
'transition-fade',
|
||||
'transition-zoom',
|
||||
'transition-slide-left',
|
||||
'transition-slide-right',
|
||||
'transition-blur',
|
||||
'transition-rotate'
|
||||
];
|
||||
|
||||
// 随机选择转场动画
|
||||
function getRandomTransition(): string {
|
||||
return transitionTypes[Math.floor(Math.random() * transitionTypes.length)];
|
||||
}
|
||||
|
||||
// 应用转场动画
|
||||
function applyTransition() {
|
||||
const bgLayer = document.getElementById('background-layer');
|
||||
if (!bgLayer) return;
|
||||
|
||||
const transitionClass = getRandomTransition();
|
||||
bgLayer.classList.add(transitionClass);
|
||||
|
||||
// 动画结束后移除类
|
||||
setTimeout(() => {
|
||||
bgLayer.classList.remove(transitionClass);
|
||||
}, 1500); // 最长动画时间
|
||||
}
|
||||
|
||||
// 重启慢慢放大动画
|
||||
function restartSlowZoom() {
|
||||
const bgLayer = document.getElementById('background-layer');
|
||||
if (!bgLayer) return;
|
||||
|
||||
// 移除动画,触发重排
|
||||
bgLayer.style.animation = 'none';
|
||||
// 强制重排
|
||||
void bgLayer.offsetHeight;
|
||||
// 重新应用动画
|
||||
bgLayer.style.animation = 'slowZoom 10s ease-out forwards';
|
||||
}
|
||||
|
||||
// 从洗牌队列中取出下一张图片(预加载后再切换)
|
||||
async function displayNextImage() {
|
||||
// 如果队列为空,重新洗牌
|
||||
@@ -232,8 +274,16 @@ async function displayNextImage() {
|
||||
// 预加载图片,确保加载完成后再切换
|
||||
const preloadImg = new Image();
|
||||
preloadImg.onload = () => {
|
||||
// 应用随机转场动画
|
||||
applyTransition();
|
||||
|
||||
// 图片加载完成,平滑切换
|
||||
randomImageUrl.value = nextImageUrl;
|
||||
|
||||
// 重启慢慢放大动画
|
||||
setTimeout(() => {
|
||||
restartSlowZoom();
|
||||
}, 100); // 等待图片切换完成
|
||||
};
|
||||
preloadImg.onerror = () => {
|
||||
// 加载失败,尝试下一张
|
||||
|
||||
Reference in New Issue
Block a user