452 lines
9.4 KiB
Vue
452 lines
9.4 KiB
Vue
<script setup>
|
||
import { ref, onMounted, computed, watch } from 'vue'
|
||
|
||
// 组件属性
|
||
const props = defineProps({
|
||
// 是否为活动状态
|
||
active: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 滚动位置,用于实现视差效果
|
||
scrollPosition: {
|
||
type: Number,
|
||
default: 0
|
||
}
|
||
})
|
||
|
||
// 组件事件
|
||
const emit = defineEmits(['collect-seal', 'play-drum', 'height-changed'])
|
||
|
||
// 是否收集福印
|
||
const sealCollected = ref(false)
|
||
|
||
// 场景高度
|
||
const sceneHeight = ref(0)
|
||
|
||
// 背景层引用
|
||
const backgroundLayerRef = ref(null)
|
||
|
||
// 人物位置
|
||
const characterPosition = ref({
|
||
x: 20,
|
||
y: 60
|
||
})
|
||
|
||
// 是否显示烟花
|
||
const showFireworks = ref(false)
|
||
|
||
// 监听scrollPosition的变化
|
||
watch(() => props.scrollPosition, (newValue, oldValue) => {
|
||
console.log('scrollPosition changed:', oldValue, '->', newValue)
|
||
console.log('showFireworks:', showFireworks.value)
|
||
})
|
||
|
||
// 计算视差效果的偏移量
|
||
const parallaxOffset = computed(() => {
|
||
// 滚动位置的1/10作为视差偏移
|
||
const offset = props.scrollPosition * 0.1
|
||
|
||
// 根据滚动位置控制人物移动(向上行走)
|
||
// 假设当滚动位置在100-500px时,人物向上移动
|
||
const scrollRange = 400 // 滚动范围
|
||
const moveRange = 30 // 人物移动范围(百分比)
|
||
|
||
if (props.scrollPosition >= 100 && props.scrollPosition <= 500) {
|
||
// 计算人物Y轴位置(从60%移动到30%)
|
||
const progress = (props.scrollPosition - 100) / scrollRange
|
||
characterPosition.value.y = 60 - (progress * moveRange)
|
||
}
|
||
|
||
// 根据页面滑动进度显示烟花(滑动到300px时显示)
|
||
showFireworks.value = props.scrollPosition >= 300
|
||
return offset
|
||
})
|
||
|
||
// 收集福印
|
||
const collectSeal = () => {
|
||
if (!sealCollected.value) {
|
||
sealCollected.value = true
|
||
emit('collect-seal')
|
||
showToast({
|
||
message: '恭喜获得非遗福印!',
|
||
icon: 'success',
|
||
duration: 2000
|
||
})
|
||
}
|
||
}
|
||
|
||
// 播放大鼓音效
|
||
const playDrum = () => {
|
||
emit('play-drum')
|
||
collectSeal()
|
||
showToast({
|
||
message: '京韵大鼓,非遗福印!',
|
||
icon: 'info',
|
||
duration: 1500
|
||
})
|
||
}
|
||
|
||
// 页面挂载时的初始化
|
||
onMounted(() => {
|
||
// 添加动画类,触发入场动画
|
||
const container = document.querySelector('.qianmen-scene-container')
|
||
if (container) {
|
||
container.classList.add('animate-in')
|
||
}
|
||
|
||
// 等待图片加载完成后测量高度
|
||
const img = backgroundLayerRef.value ? backgroundLayerRef.value.querySelector('.background-image') : null
|
||
if (img) {
|
||
// 如果图片已经加载完成
|
||
if (img.complete) {
|
||
calculateHeight()
|
||
} else {
|
||
// 图片加载完成后测量高度
|
||
img.onload = calculateHeight
|
||
}
|
||
}
|
||
})
|
||
|
||
// 计算场景高度
|
||
const calculateHeight = () => {
|
||
if (backgroundLayerRef.value) {
|
||
sceneHeight.value = backgroundLayerRef.value.offsetHeight
|
||
// 将高度发送给父组件
|
||
emit('height-changed', sceneHeight.value)
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<section class="qianmen-scene-container" :class="{ 'active': active }">
|
||
<!-- 背景图片层 -->
|
||
<div class="background-layer" ref="backgroundLayerRef" :style="{ transform: `translateY(${parallaxOffset}px)` }">
|
||
<!-- 使用复制到public目录的背景图片 -->
|
||
<img src="/static/bg/bg1.jpg" alt="前门商圈" class="background-image" />
|
||
</div>
|
||
|
||
<!-- 增强动效层 -->
|
||
<div class="enhancement-layer">
|
||
<!-- 灯笼增强动效 -->
|
||
<div class="lanterns">
|
||
<div class="lantern left-lantern">🏮</div>
|
||
<div class="lantern right-lantern">🏮</div>
|
||
</div>
|
||
|
||
<!-- 福字增强动效 -->
|
||
<div class="fu-word">福</div>
|
||
|
||
<!-- 点击提示 -->
|
||
<div class="click-indicator" :class="{ 'animate-pulse': !sealCollected }">
|
||
<div class="pulse-circle"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 大鼓交互区域 -->
|
||
<div class="drum-interactive-area" @click="playDrum">
|
||
<!-- 覆盖在图片大鼓上的点击区域 -->
|
||
</div>
|
||
|
||
<!-- 烟花效果 -->
|
||
<div class="fireworks">
|
||
<div class="firework firework-1">🎆</div>
|
||
<div class="firework firework-2">🎇</div>
|
||
<div class="firework firework-3">🎆</div>
|
||
<div class="firework firework-4">🎇</div>
|
||
</div>
|
||
|
||
<!-- 人物元素 -->
|
||
<div
|
||
class="character"
|
||
:style="{
|
||
left: `${characterPosition.x}%`,
|
||
top: `${characterPosition.y}%`,
|
||
transform: `translate(-50%, -50%)`
|
||
}"
|
||
>
|
||
🧧
|
||
</div>
|
||
|
||
<!-- 烟花效果 -->
|
||
<div class="fireworks" v-if="showFireworks">
|
||
<div class="firework firework-1">🎆</div>
|
||
<div class="firework firework-2">🎇</div>
|
||
<div class="firework firework-3">🎆</div>
|
||
<div class="firework firework-4">🎇</div>
|
||
</div>
|
||
|
||
<!-- 福印收集标记 -->
|
||
<div v-if="sealCollected" class="seal-collected-mark">
|
||
<div class="seal-icon">🏮</div>
|
||
<div class="seal-text">已收集非遗福印</div>
|
||
</div>
|
||
</section>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.qianmen-scene-container {
|
||
position: relative;
|
||
width: 100%;
|
||
height: auto; /* 高度由内容决定 */
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
background-color: #ff6b35;
|
||
}
|
||
|
||
/* 背景图片层 */
|
||
.background-layer {
|
||
position: relative;
|
||
width: 100%;
|
||
transition: transform 0.1s ease;
|
||
/* 背景图片决定容器高度 */
|
||
height: auto;
|
||
}
|
||
|
||
.background-image {
|
||
width: 100%;
|
||
height: auto;
|
||
display: block;
|
||
/* 确保图片完整显示,决定容器高度 */
|
||
object-fit: contain;
|
||
}
|
||
|
||
/* 增强动效层 */
|
||
.enhancement-layer {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 10;
|
||
}
|
||
|
||
/* 灯笼增强动效 */
|
||
.lanterns {
|
||
position: absolute;
|
||
top: 15%;
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 0 30px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.lantern {
|
||
font-size: 2.5rem;
|
||
animation: swing 3s infinite ease-in-out;
|
||
opacity: 0.9;
|
||
filter: drop-shadow(0 0 15px rgba(255, 215, 0, 0.8));
|
||
color: #ffd700;
|
||
}
|
||
|
||
.left-lantern {
|
||
animation-delay: 0s;
|
||
}
|
||
|
||
.right-lantern {
|
||
animation-delay: 1.5s;
|
||
}
|
||
|
||
@keyframes swing {
|
||
0%, 100% { transform: rotate(-10deg); }
|
||
50% { transform: rotate(10deg); }
|
||
}
|
||
|
||
/* 福字增强动效 */
|
||
.fu-word {
|
||
position: absolute;
|
||
top: 30%;
|
||
left: 65%;
|
||
transform: translateX(-50%) rotate(15deg);
|
||
font-size: 2rem;
|
||
color: #ffd700;
|
||
text-shadow: 2px 2px 10px rgba(255, 215, 0, 0.9);
|
||
animation: float 4s infinite ease-in-out;
|
||
}
|
||
|
||
@keyframes float {
|
||
0%, 100% { transform: translateX(-50%) rotate(15deg) translateY(0); }
|
||
50% { transform: translateX(-50%) rotate(15deg) translateY(-15px); }
|
||
}
|
||
|
||
/* 点击指示器 */
|
||
.click-indicator {
|
||
position: absolute;
|
||
top: 55%;
|
||
left: 75%;
|
||
transform: translate(-50%, -50%);
|
||
width: 60px;
|
||
height: 60px;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.pulse-circle {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 50%;
|
||
background-color: rgba(255, 215, 0, 0.3);
|
||
border: 2px solid rgba(255, 215, 0, 0.6);
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0% {
|
||
transform: scale(0.8);
|
||
opacity: 0.8;
|
||
}
|
||
100% {
|
||
transform: scale(2);
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
.click-indicator.animate-pulse {
|
||
display: block;
|
||
}
|
||
|
||
/* 大鼓交互区域 */
|
||
.drum-interactive-area {
|
||
position: absolute;
|
||
top: 55%;
|
||
right: 15%;
|
||
width: 120px;
|
||
height: 100px;
|
||
cursor: pointer;
|
||
z-index: 20;
|
||
}
|
||
|
||
/* 响应式调整交互区域位置 */
|
||
@media (max-width: 640px) {
|
||
.drum-interactive-area {
|
||
top: 52%;
|
||
right: 10%;
|
||
width: 100px;
|
||
height: 80px;
|
||
}
|
||
}
|
||
|
||
/* 人物元素 */
|
||
.character {
|
||
position: absolute;
|
||
font-size: 3rem;
|
||
pointer-events: none;
|
||
z-index: 20;
|
||
transition: top 0.1s linear;
|
||
filter: drop-shadow(0 0 10px rgba(255, 215, 0, 0.5));
|
||
animation: walk 1s infinite alternate;
|
||
}
|
||
|
||
@keyframes walk {
|
||
0% {
|
||
transform: translate(-50%, -50%) scale(1);
|
||
}
|
||
100% {
|
||
transform: translate(-50%, -50%) scale(1.1);
|
||
}
|
||
}
|
||
|
||
/* 烟花效果 */
|
||
.fireworks {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 20;
|
||
animation: fadeIn 0.5s ease;
|
||
}
|
||
|
||
.firework {
|
||
position: absolute;
|
||
font-size: 2rem;
|
||
opacity: 0;
|
||
animation: firework 3s infinite;
|
||
}
|
||
|
||
.firework-1 {
|
||
top: 10%;
|
||
left: 20%;
|
||
animation-delay: 0s;
|
||
}
|
||
|
||
.firework-2 {
|
||
top: 15%;
|
||
right: 25%;
|
||
animation-delay: 1s;
|
||
}
|
||
|
||
.firework-3 {
|
||
top: 8%;
|
||
right: 15%;
|
||
animation-delay: 2s;
|
||
}
|
||
|
||
.firework-4 {
|
||
top: 12%;
|
||
left: 25%;
|
||
animation-delay: 3s;
|
||
}
|
||
|
||
@keyframes firework {
|
||
0%, 100% { opacity: 0; transform: scale(0); }
|
||
50% { opacity: 1; transform: scale(1.5); }
|
||
}
|
||
|
||
/* 福印收集标记 */
|
||
.seal-collected-mark {
|
||
position: absolute;
|
||
top: 20px;
|
||
right: 20px;
|
||
background-color: rgba(255, 107, 53, 0.9);
|
||
color: #fff;
|
||
padding: 10px 15px;
|
||
border-radius: 20px;
|
||
font-size: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
animation: fadeIn 0.5s ease;
|
||
z-index: 30;
|
||
}
|
||
|
||
.seal-icon {
|
||
font-size: 20px;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; transform: translateY(-20px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
/* 入场动画 */
|
||
.qianmen-scene-container.animate-in {
|
||
animation: sceneFadeIn 1s ease-out;
|
||
}
|
||
|
||
@keyframes sceneFadeIn {
|
||
from { opacity: 0; transform: translateY(50px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 640px) {
|
||
.fu-word {
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.lantern {
|
||
font-size: 2rem;
|
||
}
|
||
|
||
.drum-interactive-area {
|
||
width: 100px;
|
||
height: 80px;
|
||
}
|
||
}
|
||
</style>
|