v1.2.4
1、增加loading组件,用于预加载scroll-view的背景图片,然后使得scroll-view进行隐藏的滚动到首页 2、调整首页滚动逻辑,使得可以完全屏蔽滚动;同时修改向上滚动逻辑
This commit is contained in:
parent
ab75f0056c
commit
e3d0ffe1e6
|
|
@ -0,0 +1,216 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, computed } from 'vue'
|
||||||
|
|
||||||
|
// 组件属性
|
||||||
|
const props = defineProps({
|
||||||
|
// 是否显示
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 组件事件
|
||||||
|
const emit = defineEmits(['loaded', 'start'])
|
||||||
|
|
||||||
|
// 加载进度
|
||||||
|
const loadingProgress = ref(0)
|
||||||
|
// 是否加载完成
|
||||||
|
const isLoadingComplete = ref(false)
|
||||||
|
// 是否显示开始按钮
|
||||||
|
const showStartButton = ref(false)
|
||||||
|
|
||||||
|
// 生成带时间戳的图片URL(避免缓存)
|
||||||
|
const generateImageUrl = (name) => {
|
||||||
|
const url = new URL(`/static/bg/${name}.jpg`, import.meta.url)
|
||||||
|
// 添加时间戳参数避免浏览器缓存
|
||||||
|
return url.href
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算开始按钮是否可见
|
||||||
|
const startButtonVisible = computed(() => {
|
||||||
|
return isLoadingComplete.value && showStartButton.value
|
||||||
|
})
|
||||||
|
|
||||||
|
// 加载图片函数
|
||||||
|
const loadImages = async () => {
|
||||||
|
// 图片名称数组
|
||||||
|
const bgImageNames = [
|
||||||
|
'bg1',
|
||||||
|
'bg2',
|
||||||
|
'bg3',
|
||||||
|
'bg4',
|
||||||
|
'bg5',
|
||||||
|
'bg_finish',
|
||||||
|
'bg_main'
|
||||||
|
]
|
||||||
|
|
||||||
|
// 生成图片URL数组
|
||||||
|
const bgImages = bgImageNames.map(name => generateImageUrl(name))
|
||||||
|
|
||||||
|
const totalImages = bgImages.length
|
||||||
|
let loadedImages = 0
|
||||||
|
|
||||||
|
// 加载每张图片
|
||||||
|
for (const imagePath of bgImages) {
|
||||||
|
try {
|
||||||
|
await loadImage(imagePath)
|
||||||
|
loadedImages++
|
||||||
|
// 更新加载进度
|
||||||
|
const progress = Math.round((loadedImages / totalImages) * 100)
|
||||||
|
loadingProgress.value = progress
|
||||||
|
|
||||||
|
// 模拟加载延迟,使进度条动画更流畅
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100))
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载图片失败:', imagePath, error)
|
||||||
|
// 即使加载失败,也继续加载其他图片
|
||||||
|
loadedImages++
|
||||||
|
loadingProgress.value = Math.round((loadedImages / totalImages) * 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载完成
|
||||||
|
isLoadingComplete.value = true
|
||||||
|
loadingProgress.value = 100
|
||||||
|
|
||||||
|
// 延迟显示开始按钮,让用户看到100%的进度
|
||||||
|
setTimeout(() => {
|
||||||
|
showStartButton.value = true
|
||||||
|
// 通知父组件加载完成
|
||||||
|
emit('loaded')
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个图片加载函数
|
||||||
|
const loadImage = (src) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image()
|
||||||
|
img.onload = resolve
|
||||||
|
img.onerror = reject
|
||||||
|
img.src = src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击开始按钮
|
||||||
|
const handleStart = () => {
|
||||||
|
emit('start')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载后开始加载图片
|
||||||
|
onMounted(() => {
|
||||||
|
loadImages()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="visible" class="loading-container">
|
||||||
|
<!-- 背景图片 -->
|
||||||
|
<div class="loading-bg">
|
||||||
|
<img src="/static/loading/loading_bg.jpg" alt="加载背景" class="bg-image" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 进度条区域 -->
|
||||||
|
<div class="progress-container">
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill" :style="{ width: `${loadingProgress}%` }"></div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-text">{{ loadingProgress }}%</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 开始按钮 -->
|
||||||
|
<div v-if="startButtonVisible" class="start-button" @click="handleStart">
|
||||||
|
<img src="/static/loading/btn_start.png" alt="开始" class="start-btn-image" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.loading-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-bg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-container {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30vh;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 500rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 20rpx;
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 10rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #FFD700;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #FFD700;
|
||||||
|
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-button {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20vh;
|
||||||
|
width: 300rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
cursor: pointer;
|
||||||
|
animation: pulse 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-btn-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -14,6 +14,7 @@ import EndPage from './EndPage.vue'
|
||||||
import LotteryFormModal from './LotteryFormModal.vue'
|
import LotteryFormModal from './LotteryFormModal.vue'
|
||||||
import AICoupletForm from './AICoupletForm.vue'
|
import AICoupletForm from './AICoupletForm.vue'
|
||||||
import CoupletDisplay from './CoupletDisplay.vue'
|
import CoupletDisplay from './CoupletDisplay.vue'
|
||||||
|
import LoadingComponent from './LoadingComponent.vue'
|
||||||
|
|
||||||
const sceneStore = useSceneStore()
|
const sceneStore = useSceneStore()
|
||||||
const collectionStore = useCollectionStore()
|
const collectionStore = useCollectionStore()
|
||||||
|
|
@ -52,6 +53,10 @@ const hasSubmittedUserInfo = ref(false)
|
||||||
const hasScrolled = ref(false)
|
const hasScrolled = ref(false)
|
||||||
// 标记是否正在自动滚动
|
// 标记是否正在自动滚动
|
||||||
const isAutoScrolling = ref(false)
|
const isAutoScrolling = ref(false)
|
||||||
|
// 是否显示加载组件
|
||||||
|
const showLoading = ref(true)
|
||||||
|
// 是否已完成图片加载
|
||||||
|
const isImagesLoaded = ref(false)
|
||||||
|
|
||||||
|
|
||||||
// 推荐关键词
|
// 推荐关键词
|
||||||
|
|
@ -140,8 +145,95 @@ const collectedSeals = computed(() => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 组件挂载后初始化
|
// 处理加载完成事件
|
||||||
onMounted(() => {
|
const handleLoadingComplete = () => {
|
||||||
|
isImagesLoaded.value = true
|
||||||
|
console.log('图片加载完成,准备初始化页面')
|
||||||
|
|
||||||
|
// 确保 scrollContainer 已初始化并滚动到最下方
|
||||||
|
ensureScrollContainerReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保 scrollContainer 已初始化并滚动到最下方
|
||||||
|
const ensureScrollContainerReady = () => {
|
||||||
|
// 等待 DOM 渲染完成
|
||||||
|
nextTick(() => {
|
||||||
|
const checkScrollContainer = () => {
|
||||||
|
if (!scrollContainer.value) {
|
||||||
|
console.log('scrollContainer 尚未初始化,延迟重试...')
|
||||||
|
setTimeout(checkScrollContainer, 100)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = scrollContainer.value
|
||||||
|
console.log('scrollContainer 已初始化:', {
|
||||||
|
scrollHeight: container.scrollHeight,
|
||||||
|
clientHeight: container.clientHeight
|
||||||
|
})
|
||||||
|
|
||||||
|
// 如果 scrollHeight 为 0,说明内容还未渲染
|
||||||
|
if (container.scrollHeight === 0) {
|
||||||
|
console.log('内容尚未渲染,延迟重试...')
|
||||||
|
setTimeout(checkScrollContainer, 100)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记正在自动滚动
|
||||||
|
isAutoScrolling.value = true
|
||||||
|
|
||||||
|
// 设置首页 section ID,使用 scroll-into-view 滚动到首页
|
||||||
|
homeSectionId.value = 'home-section'
|
||||||
|
console.log('使用 scroll-into-view 滚动到首页')
|
||||||
|
|
||||||
|
// 设置活动场景为首页
|
||||||
|
activeSceneIndex.value = scenes.value.length - 1
|
||||||
|
|
||||||
|
// 等待 scroll-into-view 生效
|
||||||
|
setTimeout(() => {
|
||||||
|
// 再次检查并滚动到最下方,确保滚动位置正确
|
||||||
|
try {
|
||||||
|
const targetScrollTop = container.scrollHeight - container.clientHeight
|
||||||
|
if (typeof container.scrollTo === 'function') {
|
||||||
|
container.scrollTo({
|
||||||
|
top: targetScrollTop,
|
||||||
|
duration: 0
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
container.scrollTop = targetScrollTop
|
||||||
|
}
|
||||||
|
console.log('已滚动到最下方,scrollTop:', container.scrollTop)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('滚动失败:', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动滚动结束
|
||||||
|
isAutoScrolling.value = false
|
||||||
|
// 强制将 hasScrolled 设置为 false,确保滑动提示能够显示
|
||||||
|
hasScrolled.value = false
|
||||||
|
console.log('scrollContainer 准备就绪,hasScrolled:', hasScrolled.value)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始检查 scrollContainer
|
||||||
|
checkScrollContainer()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理开始按钮点击事件
|
||||||
|
const handleStart = () => {
|
||||||
|
// 隐藏加载组件
|
||||||
|
showLoading.value = false
|
||||||
|
|
||||||
|
// 确保滑动提示能够显示
|
||||||
|
hasScrolled.value = false
|
||||||
|
console.log('点击开始按钮,hasScrolled:', hasScrolled.value)
|
||||||
|
|
||||||
|
// 初始化页面
|
||||||
|
initPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化页面函数
|
||||||
|
const initPage = () => {
|
||||||
// 记录页面访问
|
// 记录页面访问
|
||||||
recordPageVisit({
|
recordPageVisit({
|
||||||
user_agent: navigator.userAgent,
|
user_agent: navigator.userAgent,
|
||||||
|
|
@ -163,114 +255,15 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 添加滚动事件监听 - 使用uniapp的scroll-view事件绑定
|
// 标记页面准备就绪
|
||||||
// scroll-view 组件通过 @scroll 事件监听滚动,无需手动添加事件监听器
|
|
||||||
|
|
||||||
|
|
||||||
// 页面加载时滚动到最底部(首页)
|
|
||||||
const scrollToHomePage = () => {
|
|
||||||
// 标记正在自动滚动
|
|
||||||
isAutoScrolling.value = true
|
|
||||||
|
|
||||||
if (!scrollContainer.value) {
|
|
||||||
console.log('scrollContainer 尚未初始化')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存当前容器引用,避免异步回调中丢失
|
|
||||||
const container = scrollContainer.value
|
|
||||||
|
|
||||||
console.log('scrollContainer 已初始化:', {
|
|
||||||
element: container,
|
|
||||||
scrollHeight: container.scrollHeight,
|
|
||||||
clientHeight: container.clientHeight,
|
|
||||||
scrollTop: container.scrollTop,
|
|
||||||
classList: container.classList
|
|
||||||
})
|
|
||||||
|
|
||||||
// 如果scrollHeight为0,说明内容还未渲染
|
|
||||||
if (container.scrollHeight === 0) {
|
|
||||||
console.log('内容尚未渲染,延迟重试...')
|
|
||||||
setTimeout(scrollToHomePage, 100)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 首页是最后一个场景,索引为 scenes.value.length - 1
|
|
||||||
// 应该位于页面最底部
|
|
||||||
const homeIndex = scenes.value.length - 1
|
|
||||||
|
|
||||||
// 方法1: 使用 scroll-into-view(uniapp 原生支持)
|
|
||||||
console.log('使用 scroll-into-view 滚动到首页')
|
|
||||||
homeSectionId.value = 'home-section'
|
|
||||||
|
|
||||||
// 设置活动场景为首页
|
|
||||||
activeSceneIndex.value = homeIndex
|
|
||||||
|
|
||||||
// 设置活动场景为首页
|
|
||||||
activeSceneIndex.value = homeIndex
|
|
||||||
|
|
||||||
// 验证滚动是否成功,如果不成功,延迟后重试
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!container) {
|
|
||||||
console.log('scrollContainer 已卸载')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('验证滚动结果:', {
|
|
||||||
currentScrollTop: container.scrollTop,
|
|
||||||
scrollHeight: container.scrollHeight,
|
|
||||||
clientHeight: container.clientHeight,
|
|
||||||
isAtBottom: Math.abs(container.scrollTop - (container.scrollHeight - container.clientHeight)) < 50
|
|
||||||
})
|
|
||||||
|
|
||||||
// 检查是否已经滚动到底部
|
|
||||||
const isAtBottom = Math.abs(container.scrollTop - (container.scrollHeight - container.clientHeight)) < 50
|
|
||||||
|
|
||||||
if (!isAtBottom) {
|
|
||||||
console.log('滚动验证失败,使用备用方法重试...')
|
|
||||||
// 方法2: 使用 scrollTo 或 scrollTop
|
|
||||||
try {
|
|
||||||
const targetScrollTop = container.scrollHeight - container.clientHeight
|
|
||||||
if (typeof container.scrollTo === 'function') {
|
|
||||||
container.scrollTo({
|
|
||||||
top: targetScrollTop,
|
|
||||||
duration: 0
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
container.scrollTop = targetScrollTop
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('备用方法失败:', error)
|
|
||||||
container.scrollTop = container.scrollHeight - container.clientHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
// 再次验证后显示容器
|
|
||||||
setTimeout(() => {
|
|
||||||
// 标记页面准备就绪,隐藏加载提示并显示页面
|
|
||||||
isPageReady.value = true
|
|
||||||
titleImageShown.value = true
|
titleImageShown.value = true
|
||||||
// 自动滚动结束
|
|
||||||
isAutoScrolling.value = false
|
isAutoScrolling.value = false
|
||||||
console.log('设置 isPageReady = true,准备显示页面')
|
console.log('页面准备就绪')
|
||||||
}, 50)
|
|
||||||
} else {
|
|
||||||
console.log('成功滚动到首页')
|
|
||||||
// 滚动成功后显示容器
|
|
||||||
// 标记页面准备就绪,隐藏加载提示并显示页面
|
|
||||||
isPageReady.value = true
|
|
||||||
titleImageShown.value = true
|
|
||||||
// 自动滚动结束
|
|
||||||
isAutoScrolling.value = false
|
|
||||||
console.log('设置 isPageReady = true,准备显示页面')
|
|
||||||
}
|
|
||||||
}, 300)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始滚动到首页 - 延迟更长时间确保内容渲染
|
// 组件挂载后初始化
|
||||||
setTimeout(scrollToHomePage, 800)
|
onMounted(() => {
|
||||||
|
console.log('SinglePageContainer 组件挂载')
|
||||||
// 额外的确保措施,等待更长时间后再次尝试
|
|
||||||
setTimeout(scrollToHomePage, 1500)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 处理滚动事件(从下往上滑动)
|
// 处理滚动事件(从下往上滑动)
|
||||||
|
|
@ -512,15 +505,15 @@ onUnmounted(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="single-page-wrapper">
|
<div class="single-page-wrapper">
|
||||||
<!-- 加载提示 -->
|
<!-- 加载组件 -->
|
||||||
<div class="loading-hint" v-if="!isPageReady">
|
<LoadingComponent
|
||||||
<div class="loading-spinner"></div>
|
v-if="showLoading"
|
||||||
<p>正在加载...</p>
|
@loaded="handleLoadingComplete"
|
||||||
</div>
|
@start="handleStart"
|
||||||
|
/>
|
||||||
|
|
||||||
<scroll-view
|
<scroll-view
|
||||||
class="single-page-container"
|
class="single-page-container"
|
||||||
:class="{ 'visible': isPageReady }"
|
|
||||||
ref="scrollContainer"
|
ref="scrollContainer"
|
||||||
scroll-y="true"
|
scroll-y="true"
|
||||||
scroll-with-animation="true"
|
scroll-with-animation="true"
|
||||||
|
|
@ -654,44 +647,6 @@ onUnmounted(() => {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 加载提示样式 */
|
|
||||||
.loading-hint {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
z-index: 1000;
|
|
||||||
background: rgba(253, 233, 223, 0.95);
|
|
||||||
padding: 30px 40px;
|
|
||||||
border-radius: 15px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spinner {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border: 3px solid #f3f3f3;
|
|
||||||
border-top: 3px solid #FF6B35;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-hint p {
|
|
||||||
color: #FF6B35;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.single-page-container {
|
.single-page-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -699,17 +654,11 @@ onUnmounted(() => {
|
||||||
overflow-y: scroll; /* 改为 scroll 确保可以滚动 */
|
overflow-y: scroll; /* 改为 scroll 确保可以滚动 */
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
-webkit-overflow-scrolling: touch; /* 启用iOS平滑滚动 */
|
-webkit-overflow-scrolling: touch; /* 启用iOS平滑滚动 */
|
||||||
/* 使用 visibility 而不是 opacity,确保完全不可见且不可交互 */
|
|
||||||
visibility: hidden;
|
|
||||||
touch-action: pan-y; /* 允许垂直方向的触摸滚动 */
|
touch-action: pan-y; /* 允许垂直方向的触摸滚动 */
|
||||||
user-select: none; /* 防止触摸时文本被选中 */
|
user-select: none; /* 防止触摸时文本被选中 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.single-page-container.visible {
|
|
||||||
visibility: visible;
|
|
||||||
/* 添加淡入效果 */
|
|
||||||
animation: fadeIn 0.4s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; }
|
from { opacity: 0; }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue