|
@@ -49,7 +49,10 @@
|
|
|
hide: hotVisible && checkedHotId !== 2
|
|
|
}"
|
|
|
>
|
|
|
- <img src="./images/bamboo2.png">
|
|
|
+ <img
|
|
|
+ src="./images/bamboo2.png"
|
|
|
+ @load="handleBambooOffset(2)"
|
|
|
+ >
|
|
|
</div>
|
|
|
<div
|
|
|
class="bamboo-hot2__hot b2"
|
|
@@ -67,7 +70,10 @@
|
|
|
hide: hotVisible && checkedHotId !== 3
|
|
|
}"
|
|
|
>
|
|
|
- <img src="./images/bamboo3.png">
|
|
|
+ <img
|
|
|
+ src="./images/bamboo3.png"
|
|
|
+ @load="handleBambooOffset(3)"
|
|
|
+ >
|
|
|
|
|
|
<div
|
|
|
class="bamboo-hot2__hot"
|
|
@@ -86,7 +92,10 @@
|
|
|
hide: hotVisible && checkedHotId !== 4
|
|
|
}"
|
|
|
>
|
|
|
- <img src="./images/bamboo4.png">
|
|
|
+ <img
|
|
|
+ src="./images/bamboo4.png"
|
|
|
+ @load="handleBambooOffset(4)"
|
|
|
+ >
|
|
|
|
|
|
<div
|
|
|
class="bamboo-hot2__hot"
|
|
@@ -132,7 +141,10 @@
|
|
|
hide: hotVisible && checkedHotId !== 8
|
|
|
}"
|
|
|
>
|
|
|
- <img src="./images/bamboo8.png">
|
|
|
+ <img
|
|
|
+ src="./images/bamboo8.png"
|
|
|
+ @load="handleBambooOffset(8)"
|
|
|
+ >
|
|
|
|
|
|
<div
|
|
|
class="bamboo-hot2__hot"
|
|
@@ -199,6 +211,7 @@
|
|
|
class="bamboo-hot2-bg-wrap"
|
|
|
>
|
|
|
<img
|
|
|
+ v-if="bgImgLoaded"
|
|
|
class="bamboo-hot2__grass"
|
|
|
:class="{
|
|
|
hide: hotVisible
|
|
@@ -209,6 +222,10 @@
|
|
|
<img
|
|
|
class="bamboo-hot2__bg"
|
|
|
src="./images/bg.png"
|
|
|
+ :style="{
|
|
|
+ filter: hotVisible ? 'saturate(1.3) brightness(0.95)' : 'none'
|
|
|
+ }"
|
|
|
+ @load="bgImgLoaded = true"
|
|
|
>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -226,16 +243,16 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref } from 'vue'
|
|
|
+import { ref, watch, onBeforeUnmount } from 'vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
import useSizeAdapt from "@/useFunctions/useSizeAdapt"
|
|
|
|
|
|
-const ITEM_SCROLL_MAP = {
|
|
|
- 1: 10,
|
|
|
+let itemScrollMap = {
|
|
|
+ 1: 0,
|
|
|
2: 166,
|
|
|
- 3: 231,
|
|
|
- 4: 420,
|
|
|
- 8: 958
|
|
|
+ 3: 201,
|
|
|
+ 4: 450,
|
|
|
+ 8: 1048
|
|
|
}
|
|
|
const ITEM_INFO_MAP = {
|
|
|
1: {
|
|
@@ -281,13 +298,13 @@ const ITEM_INFO_MAP = {
|
|
|
},
|
|
|
}
|
|
|
|
|
|
+const bgImgLoaded = ref(false)
|
|
|
const {
|
|
|
windowSizeInCssForRef,
|
|
|
windowSizeWhenDesignForRef,
|
|
|
} = useSizeAdapt()
|
|
|
const router = useRouter()
|
|
|
-let startX = 0
|
|
|
-let lastStartX = 0
|
|
|
+
|
|
|
const bambooWrap = ref()
|
|
|
const bambooWrapBg = ref()
|
|
|
|
|
@@ -298,42 +315,126 @@ const handleHot = (id) => {
|
|
|
checkedHotId.value = id
|
|
|
hotVisible.value = true
|
|
|
|
|
|
+ cancelAnimationFrame(animationFrameId.value)
|
|
|
bambooWrap.value.scrollTo({
|
|
|
- left: ITEM_SCROLL_MAP[id],
|
|
|
+ left: itemScrollMap[id],
|
|
|
behavior: 'smooth'
|
|
|
})
|
|
|
-
|
|
|
- lastStartX = ITEM_SCROLL_MAP[id]
|
|
|
+ translateX.value = itemScrollMap[id]
|
|
|
}
|
|
|
|
|
|
-const handleTouchstart = (v) => {
|
|
|
- if (hotVisible.value) return
|
|
|
-
|
|
|
- startX = v.changedTouches[0].pageX
|
|
|
+const handleBambooOffset = (target) => {
|
|
|
+ const offset = window.innerWidth / 6
|
|
|
+ const left = document.getElementsByClassName(`bamboo-hot2-b${target}`)?.[0].getBoundingClientRect().left
|
|
|
+ let temp = 0
|
|
|
+ switch (target) {
|
|
|
+ case 3:
|
|
|
+ temp = window.innerWidth / 3
|
|
|
+ break
|
|
|
+ case 4:
|
|
|
+ temp = -(window.innerWidth * 0.25)
|
|
|
+ break
|
|
|
+ case 8:
|
|
|
+ temp = -(window.innerWidth * 0.7)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ itemScrollMap[target] = left - offset + temp
|
|
|
}
|
|
|
-const handleTouchmove = (v) => {
|
|
|
- v.preventDefault()
|
|
|
- if (hotVisible.value) return
|
|
|
|
|
|
- const wrapWidth = bambooWrapBg.value.scrollWidth - window.innerWidth
|
|
|
- const moveX = startX - v.changedTouches[0].pageX
|
|
|
+// 动画帧相关
|
|
|
+const lastAnimationTimeStamp = ref(0)
|
|
|
+const animationFrameId = ref(0)
|
|
|
+const moveSpeed = ref(0)
|
|
|
+const translateX = ref(0)
|
|
|
+const maxTranslateXLength = ref(0)
|
|
|
+const lastMoveEventTimeStamp = ref(0)
|
|
|
+const isMouseDown = ref(false)
|
|
|
+const isMove = ref(false)
|
|
|
+const lastTouchPos = ref(0)
|
|
|
+
|
|
|
+watch([bambooWrapBg, bgImgLoaded], () => {
|
|
|
+ if (!bgImgLoaded.value) return
|
|
|
+
|
|
|
+ maxTranslateXLength.value = bambooWrapBg.value ? bambooWrapBg.value.scrollWidth - window.innerWidth : 0
|
|
|
+ animationFrameId.value = requestAnimationFrame(animationFrameTask)
|
|
|
+})
|
|
|
+
|
|
|
+const animationFrameTask = () => {
|
|
|
+ const timeStamp = Date.now()
|
|
|
+ const timeElapsed = timeStamp - lastAnimationTimeStamp.value
|
|
|
+
|
|
|
+ // 速度减慢
|
|
|
+ if (moveSpeed.value > 0) {
|
|
|
+ moveSpeed.value -= 0.003 * timeElapsed
|
|
|
+ if (moveSpeed.value < 0) {
|
|
|
+ moveSpeed.value = 0
|
|
|
+ }
|
|
|
+ } else if (moveSpeed.value < 0) {
|
|
|
+ moveSpeed.value += 0.003 * timeElapsed
|
|
|
+ if (moveSpeed.value > 0) {
|
|
|
+ moveSpeed.value = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据速度更新距离
|
|
|
+ translateX.value += moveSpeed.value * timeElapsed
|
|
|
+ if (translateX.value < 0) {
|
|
|
+ translateX.value = 0
|
|
|
+ } else if (translateX.value > maxTranslateXLength.value) {
|
|
|
+ translateX.value = maxTranslateXLength.value
|
|
|
+ moveSpeed.value = 0
|
|
|
+ }
|
|
|
|
|
|
- bambooWrap.value.scrollTo({
|
|
|
- left: Math.min(moveX + lastStartX, wrapWidth),
|
|
|
+ bambooWrap.value?.scrollTo({
|
|
|
+ left: translateX.value,
|
|
|
behavior: 'instant'
|
|
|
})
|
|
|
+ lastAnimationTimeStamp.value = timeStamp
|
|
|
+ animationFrameId.value = requestAnimationFrame(animationFrameTask)
|
|
|
+}
|
|
|
+
|
|
|
+const handleTouchstart = (e) => {
|
|
|
+ if (hotVisible.value) return
|
|
|
+
|
|
|
+ isMouseDown.value = true
|
|
|
+ moveSpeed.value = 0
|
|
|
+ lastMoveEventTimeStamp.value = 0
|
|
|
+ lastAnimationTimeStamp.value = Date.now()
|
|
|
+ lastTouchPos.value = e.changedTouches[0].clientX
|
|
|
+}
|
|
|
+const handleTouchmove = (e) => {
|
|
|
+ e.preventDefault()
|
|
|
+ if (hotVisible.value || !isMouseDown.value || !e.changedTouches.length) return
|
|
|
+
|
|
|
+ if (
|
|
|
+ lastMoveEventTimeStamp.value &&
|
|
|
+ e.timeStamp - lastMoveEventTimeStamp.value > 1
|
|
|
+ ) {
|
|
|
+ // 更新speed
|
|
|
+ isMove.value = true
|
|
|
+ const currentMoveSpeed =
|
|
|
+ (-(e.changedTouches[0].clientX - lastTouchPos.value) /
|
|
|
+ (e.timeStamp - lastMoveEventTimeStamp.value)) *
|
|
|
+ 1.5
|
|
|
+ moveSpeed.value = moveSpeed.value * 0.9 + currentMoveSpeed * 0.1
|
|
|
+ lastTouchPos.value = e.changedTouches[0].clientX
|
|
|
+ }
|
|
|
+ lastMoveEventTimeStamp.value = e.timeStamp
|
|
|
}
|
|
|
-const handleTouchend = (v) => {
|
|
|
+const handleTouchend = () => {
|
|
|
if (hotVisible.value) return
|
|
|
|
|
|
- const wrapWidth = bambooWrapBg.value.scrollWidth - window.innerWidth
|
|
|
- lastStartX = Math.min(Math.max(startX - v.changedTouches[0].pageX + lastStartX, 0), wrapWidth)
|
|
|
+ isMouseDown.value = false
|
|
|
+ setTimeout(() => {
|
|
|
+ isMove.value = false
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
const goBack = () => {
|
|
|
if (hotVisible.value) {
|
|
|
hotVisible.value = false
|
|
|
checkedHotId.value = 0
|
|
|
+ animationFrameId.value = requestAnimationFrame(animationFrameTask)
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -344,6 +445,10 @@ const goBack = () => {
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ cancelAnimationFrame(animationFrameId.value)
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
|
@@ -357,6 +462,7 @@ img {
|
|
|
|
|
|
.hide {
|
|
|
opacity: 0 !important;
|
|
|
+ animation: none !important;
|
|
|
}
|
|
|
|
|
|
[class^="bamboo-hot2-b"] {
|
|
@@ -429,6 +535,7 @@ img {
|
|
|
font-size: 12px;
|
|
|
font-family: KaiTi;
|
|
|
writing-mode: vertical-rl;
|
|
|
+ animation: breathing linear 2s infinite;
|
|
|
|
|
|
&::before {
|
|
|
content: '';
|
|
@@ -441,7 +548,7 @@ img {
|
|
|
}
|
|
|
&-b1 {
|
|
|
left: calc(50 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(20 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'))) scale(0.8);
|
|
|
|
|
|
.bamboo-hot2__hot {
|
|
|
top: calc(340 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
@@ -450,18 +557,18 @@ img {
|
|
|
}
|
|
|
&-b2 {
|
|
|
left: calc(250 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(10 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
z-index: 2;
|
|
|
}
|
|
|
.bamboo-hot2__hot.b2 {
|
|
|
top: calc(200 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
left: calc(305 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(10 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
z-index: 4;
|
|
|
}
|
|
|
&-b3 {
|
|
|
- left: calc(155 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(5px);
|
|
|
+ left: calc(140 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
+ transform: translateZ(calc(20 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'))) scale(0.8);
|
|
|
|
|
|
.bamboo-hot2__hot {
|
|
|
top: calc(300 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
@@ -470,7 +577,7 @@ img {
|
|
|
}
|
|
|
&-b4 {
|
|
|
left: calc(600 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(5px);
|
|
|
+ transform: translateZ(calc(15 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'))) scale(0.85);
|
|
|
|
|
|
.bamboo-hot2__hot {
|
|
|
top: calc(220 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
@@ -479,20 +586,20 @@ img {
|
|
|
}
|
|
|
&-b5 {
|
|
|
left: calc(1050 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(20 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'))) scale(0.8);
|
|
|
}
|
|
|
&-b6 {
|
|
|
left: calc(1170 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(15px);
|
|
|
+ transform: translateZ(calc(15 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
}
|
|
|
&-b7 {
|
|
|
left: calc(1050 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(10 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
z-index: 2;
|
|
|
}
|
|
|
&-b8 {
|
|
|
left: calc(1180 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(5px);
|
|
|
+ transform: translateZ(calc(25 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'))) scale(0.8);
|
|
|
|
|
|
.bamboo-hot2__hot {
|
|
|
top: calc(320 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
@@ -501,30 +608,30 @@ img {
|
|
|
}
|
|
|
&-b9 {
|
|
|
left: calc(1480 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(20 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'))) scale(0.82);
|
|
|
}
|
|
|
&-b10 {
|
|
|
left: calc(1810 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(10 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
}
|
|
|
&-b11 {
|
|
|
left: calc(1790 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(5px);
|
|
|
+ transform: translateZ(calc(5 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
z-index: 2;
|
|
|
}
|
|
|
&-b12 {
|
|
|
left: calc(1600 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(15px);
|
|
|
+ transform: translateZ(calc(15 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
z-index: 2;
|
|
|
}
|
|
|
&-b13 {
|
|
|
left: calc(2050 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(15px);
|
|
|
+ transform: translateZ(calc(15 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef')));
|
|
|
z-index: 2;
|
|
|
}
|
|
|
&-b14 {
|
|
|
left: calc(2220 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'));
|
|
|
- transform: translateZ(10px);
|
|
|
+ transform: translateZ(calc(30 /v-bind('windowSizeWhenDesignForRef')* v-bind('windowSizeInCssForRef'))) scale(0.7);
|
|
|
}
|
|
|
&.wrap-hide {
|
|
|
&::before,
|
|
@@ -589,4 +696,16 @@ img {
|
|
|
transition: opacity 0.5s ease-in-out;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+@keyframes breathing {
|
|
|
+ 0% {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ 50% {
|
|
|
+ opacity: 0.3;
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|