diff --git a/components/DongzhimenScene.vue b/components/DongzhimenScene.vue index 5aa807b..07a07e3 100644 --- a/components/DongzhimenScene.vue +++ b/components/DongzhimenScene.vue @@ -39,6 +39,124 @@ const handleFuClick = () => { emit('collect-seal') } +// 拖拽状态 +const isDragging = ref(false) +const showDuck = ref(false) +const deskImage = ref('/static/dzm/img_desk1.png') +const showGuideElements = ref(true) + +// 鸭子元素引用 +const duckElement = ref(null) + +// 鸭子当前位置(使用普通变量,避免响应式带来的性能开销) +let duckX = 0 +let duckY = 0 + +// 拖拽开始区域 (540, 1781, 100, 100) 的中心点 +const dragStartArea = { x: 590, y: 1831 } + +// 目标区域 (餐桌区域: 13, 1665, 441, 382) +const targetArea = { x: 100, y: 1750, width: 300, height: 200 } + +// 开始拖拽 +const startDrag = (e) => { + e.preventDefault() + + // 如果已经在拖拽中,先结束之前的 + if (isDragging.value) { + endDrag() + } + + isDragging.value = true + showDuck.value = true + + // 获取触摸或鼠标位置 + const clientX = e.touches ? e.touches[0].clientX : e.clientX + const clientY = e.touches ? e.touches[0].clientY : e.clientY + + // 设置鸭子初始位置 + updateDuckPosition(clientX, clientY) + + // 先移除可能存在的旧监听器,防止重复绑定 + document.removeEventListener('mousemove', onDrag) + document.removeEventListener('mouseup', endDrag) + document.removeEventListener('touchmove', onDrag) + document.removeEventListener('touchend', endDrag) + + // 添加全局事件监听 + document.addEventListener('mousemove', onDrag) + document.addEventListener('mouseup', endDrag) + document.addEventListener('touchmove', onDrag, { passive: false }) + document.addEventListener('touchend', endDrag) +} + +// 拖拽中 +const onDrag = (e) => { + if (!isDragging.value) return + e.preventDefault() + + const clientX = e.touches ? e.touches[0].clientX : e.clientX + const clientY = e.touches ? e.touches[0].clientY : e.clientY + + updateDuckPosition(clientX, clientY) +} + +// 更新鸭子位置 - 直接操作 DOM 实现硬件加速 +const updateDuckPosition = (clientX, clientY) => { + duckX = clientX + duckY = clientY + + if (duckElement.value) { + // 使用 transform3d 启用 GPU 加速 + duckElement.value.style.transform = `translate3d(${clientX}px, ${clientY}px, 0) translate(-50%, -50%) scale(1.2)` + } +} + +// 结束拖拽 +const endDrag = () => { + if (!isDragging.value) return + + // 获取容器在视口中的位置 + const container = document.querySelector('.dongzhimen-scene-container') + if (container) { + const rect = container.getBoundingClientRect() + // 鸭子相对于容器的位置 + const duckRelX = duckX - rect.left + const duckRelY = duckY - rect.top + + // 将 rpx 转换为 px (假设设计稿宽度 750rpx,实际宽度通过 rect.width 计算) + const rpxToPx = rect.width / 750 + const targetX = targetArea.x * rpxToPx + const targetY = targetArea.y * rpxToPx + const targetW = targetArea.width * rpxToPx + const targetH = targetArea.height * rpxToPx + + const inTargetArea = ( + duckRelX >= targetX && + duckRelX <= targetX + targetW && + duckRelY >= targetY && + duckRelY <= targetY + targetH + ) + + if (inTargetArea) { + // 更换餐桌图片 + deskImage.value = '/static/dzm/img_desk2.png' + // 隐藏引导元素 + showGuideElements.value = false + } + } + + // 隐藏鸭子 + showDuck.value = false + isDragging.value = false + + // 移除全局事件监听 + document.removeEventListener('mousemove', onDrag) + document.removeEventListener('mouseup', endDrag) + document.removeEventListener('touchmove', onDrag) + document.removeEventListener('touchend', endDrag) +} + // 页面挂载时的初始化 onMounted(() => { // 添加动画类,触发入场动画 @@ -75,6 +193,29 @@ onMounted(() => { alt="新春祝福" class="sq-image" /> + + + 餐桌 + 灶台 + 线条 + 手势 + + +
+ + + 烤鸭 @@ -319,6 +460,82 @@ onMounted(() => { animation: fadeIn 0.5s ease; } +/* 装饰图片 */ +.deco-img { + position: absolute; + z-index: 25; +} + +.desk-img { + left: 13rpx; + top: 1665rpx; + width: 441rpx; + height: 382rpx; +} + +.stove-img { + left: 492rpx; + top: 1711rpx; + width: 241rpx; + height: 363rpx; +} + +.line-img { + left: 250rpx; + top: 1842rpx; + width: 360rpx; + height: 80rpx; +} + +.hand-img { + left: 440rpx; + top: 1900rpx; + width: 38rpx; + height: 40rpx; + animation: arcSlideLeft 1.2s ease-in-out infinite; +} + +/* 向左弧形滑动动效 */ +@keyframes arcSlideLeft { + 0% { + transform: translateX(0) translateY(0); + opacity: 1; + } + + 100% { + transform: translateX(-80rpx) translateY(3rpx); + opacity: 1; + } +} + +/* 拖拽触发区域 */ +.drag-trigger-area { + position: absolute; + left: 540rpx; + top: 1781rpx; + width: 100rpx; + height: 100rpx; + cursor: grab; + z-index: 30; +} + +.drag-trigger-area:active { + cursor: grabbing; +} + +/* 跟随拖拽的鸭子图片 */ +.drag-duck { + position: fixed; + left: 0; + top: 0; + width: 54rpx; + height: 105rpx; + opacity: 0.8; + pointer-events: none; + z-index: 1000; + will-change: transform; +} + /* 响应式设计 */ @media (max-width: 640px) { .fu-word { diff --git a/components/ImageGalleryModal.vue b/components/ImageGalleryModal.vue new file mode 100644 index 0000000..fe6ae07 --- /dev/null +++ b/components/ImageGalleryModal.vue @@ -0,0 +1,208 @@ + + + + + \ No newline at end of file diff --git a/components/LongfusiScene.vue b/components/LongfusiScene.vue index 2bb23c2..4dce69f 100644 --- a/components/LongfusiScene.vue +++ b/components/LongfusiScene.vue @@ -1,6 +1,7 @@