hldy_app/component/public/newgame/arrowkeys.vue

246 lines
6.9 KiB
Vue
Raw Normal View History

2025-08-13 17:19:40 +08:00
<template>
<view class="move-circle" :style="{ bottom: `${movebottom}rpx`, left: `${moveleft}rpx` }" @touchend="onLongPressEnd"
@touchcancel="onLongPressEnd">
<!-- 返回 -->
2025-08-21 16:51:53 +08:00
<view :class="beblue === 5 ? 'click-box-target' : 'click-box'" @tap="onTap(5)" style="position: relative;"
2025-08-13 17:19:40 +08:00
@longpress="(e) => onLongPressStart(5, e)">
2025-08-21 16:51:53 +08:00
<image :src="`/static/index/newruler/${beblue === 5 ? 1:0}.png`" style="position: absolute;width: 100%;
height: 100%;" />
<span style="z-index: 1;font-size: 30rpx;" :class="beblue === 5 ? 'grad-text' : ''">{{leftbuttonname}}</span>
2025-08-13 17:19:40 +08:00
</view>
<!-- -->
2025-08-21 16:51:53 +08:00
<view :class="beblue === 0 ? 'click-box-target' : 'click-box'" @tap="onTap(0)" style="position: relative;"
2025-08-13 17:19:40 +08:00
@longpress="(e) => onLongPressStart(0, e)">
2025-08-21 16:51:53 +08:00
<image :src="`/static/index/newruler/${beblue === 0 ? 1:0}.png`" style="position: absolute;width: 100%;
height: 100%;" />
<image :src="`/static/index/newruler/fangxiang${beblue===0 ? 'target' : ''}.png`" class="image-photo" />
2025-08-13 17:19:40 +08:00
</view>
<!-- 确定 -->
2025-08-21 16:51:53 +08:00
<view :class="beblue === 4 ? 'click-box-target' : 'click-box'" @tap="onTap(4)" style="position: relative;"
2025-08-13 17:19:40 +08:00
@longpress="(e) => onLongPressStart(4, e)">
2025-08-21 16:51:53 +08:00
<image :src="`/static/index/newruler/${beblue === 4 ? 1:0}.png`" style="position: absolute;width: 100%;
height: 100%;" />
<span style="z-index: 1;font-size: 30rpx;" :class="beblue === 4 ? 'grad-text' : ''">{{rightbuttonname}}</span>
2025-08-13 17:19:40 +08:00
</view>
2025-08-21 16:51:53 +08:00
<!-- -->
<view :class="beblue === 3 ? 'click-box-target' : 'click-box'" @tap="onTap(3)" style="position: relative;"
2025-08-13 17:19:40 +08:00
@longpress="(e) => onLongPressStart(3, e)">
2025-08-21 16:51:53 +08:00
<image :src="`/static/index/newruler/${beblue === 3 ? 1:0}.png`" style="position: absolute;width: 100%;
height: 100%;" />
<image style="transform: rotate(270deg);transform-origin: center;" :src="`/static/index/newruler/fangxiang${beblue===3 ? 'target' : ''}.png`"
class="image-photo" />
2025-08-13 17:19:40 +08:00
</view>
<!-- -->
2025-08-21 16:51:53 +08:00
<view :class="beblue === 2 ? 'click-box-target' : 'click-box'" @tap="onTap(2)" style="position: relative;"
2025-08-13 17:19:40 +08:00
@longpress="(e) => onLongPressStart(2, e)">
2025-08-21 16:51:53 +08:00
<image :src="`/static/index/newruler/${beblue === 2 ? 1:0}.png`" style="position: absolute;width: 100%;
height: 100%;" />
<image style="transform: rotate(180deg);transform-origin: center;" :src="`/static/index/newruler/fangxiang${beblue===2 ? 'target' : ''}.png`" class="image-photo" />
2025-08-13 17:19:40 +08:00
</view>
2025-08-21 16:51:53 +08:00
<!-- -->
<view :class="beblue === 1 ? 'click-box-target' : 'click-box'" @tap="onTap(1)" style="position: relative;"
2025-08-13 17:19:40 +08:00
@longpress="(e) => onLongPressStart(1, e)">
2025-08-21 16:51:53 +08:00
<image :src="`/static/index/newruler/${beblue === 1 ? 1:0}.png`" style="position: absolute;width: 100%;
height: 100%;" />
<image style="transform: rotate(90deg);transform-origin: center;" :src="`/static/index/newruler/fangxiang${beblue===1 ? 'target' : ''}.png`" class="image-photo" />
2025-08-13 17:19:40 +08:00
</view>
</view>
</template>
<script setup lang="ts">
import { ref, onBeforeUnmount } from 'vue'
const emit = defineEmits<{ (e : 'movecard', dir : number) : void }>()
let clickResetTimer : ReturnType<typeof setTimeout> | null = null
let longPressInterval : ReturnType<typeof setInterval> | null = null
let isLongPress = false
const beblue = ref<number>(-1)
let activeLongPressDir : number | null = null
const props = defineProps({
movebottom: {
type: Number,
2025-08-21 16:51:53 +08:00
default: 30,
2025-08-13 17:19:40 +08:00
},
moveleft: {
type: Number,
2025-08-21 16:51:53 +08:00
default: 10,
},
leftbuttonname: {
type: String,
default: "返回"
},
rightbuttonname: {
type: String,
default: "确定"
2025-08-13 17:19:40 +08:00
},
})
function clearClickResetTimer() {
if (clickResetTimer) {
clearTimeout(clickResetTimer)
clickResetTimer = null
}
}
function clearLongPressInterval() {
if (longPressInterval) {
clearInterval(longPressInterval)
longPressInterval = null
}
isLongPress = false
activeLongPressDir = null
}
// 单击(或短按)
function onTap(dir : number) {
// 立刻触发一次
clearLongPressInterval()
clearClickResetTimer()
beblue.value = dir
emit('movecard', dir)
// 800ms 后恢复(如果期间有新点击会清除并重置)
clickResetTimer = setTimeout(() => {
beblue.value = -1
clickResetTimer = null
}, 500)
}
// 长按开始(由 longpress 事件触发)
function onLongPressStart(dir : number, e ?: any) {
// 先清理点击计时器,确保长按状态保持
clearClickResetTimer()
clearLongPressInterval()
beblue.value = dir
emit('movecard', dir)
// 开始每 500ms 发一次
activeLongPressDir = dir
isLongPress = true
longPressInterval = setInterval(() => {
if (activeLongPressDir !== null) emit('movecard', activeLongPressDir)
}, 500)
}
// 长按结束touchend / touchcancel
function onLongPressEnd() {
// 如果没有长按在进行,直接返回(防止意外触发)
if (!isLongPress) return
// 停止 interval
clearLongPressInterval()
// 0.8s 后恢复选中态
clearClickResetTimer()
clickResetTimer = setTimeout(() => {
beblue.value = -1
clickResetTimer = null
}, 500)
}
onBeforeUnmount(() => {
clearClickResetTimer()
clearLongPressInterval()
})
</script>
<style lang="less" scoped>
.move-circle {
position: absolute;
bottom: 0rpx;
left: 0rpx;
2025-08-21 16:51:53 +08:00
width: 500rpx;
2025-08-13 17:19:40 +08:00
display: flex;
flex-wrap: wrap;
z-index: 99;
touch-action: none;
}
.click-box,
.click-box-target {
2025-08-21 16:51:53 +08:00
// background-color: red;
width: 150rpx;
height: 137rpx;
2025-08-13 17:19:40 +08:00
display: flex;
justify-content: center;
align-items: center;
2025-08-21 16:51:53 +08:00
margin-left: 0rpx;
// border-radius: 30rpx;
2025-08-13 17:19:40 +08:00
font-size: 28rpx;
transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.25s ease;
-webkit-tap-highlight-color: transparent;
2025-08-21 16:51:53 +08:00
margin-bottom: 10rpx;
2025-08-13 17:19:40 +08:00
}
.click-box {
color: #888d99;
}
/* 选中态:背景径向渐变 + 中心缩放动画(从中间放大再回到原样) */
.click-box-target {
color: transparent;
/* 文字使用渐变填充 */
animation: scalePulse 360ms cubic-bezier(.2, .8, .2, 1);
transform-origin: center center;
}
@keyframes scalePulse {
2025-08-21 16:51:53 +08:00
0% {
transform: scale(1);
}
25% {
/* 先收缩一点点 */
transform: scale(0.94);
}
65% {
/* 再放大到略超出的感觉 */
transform: scale(1.08);
}
100% {
transform: scale(1);
}
2025-08-13 17:19:40 +08:00
}
/* 文本渐变(用于返回/确定文字) */
.grad-text {
background-image: linear-gradient(90deg, #5b8bb3, #87a1bd);
background-size: 200% 100%;
background-position: 0% 50%;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
transition: background-position 0.8s linear;
}
/* 选中时文字渐变滚动效果 */
.click-box-target .grad-text {
background-position: 100% 50%;
}
.image-photo {
2025-08-21 16:51:53 +08:00
width: 25%;
height: 25%;
2025-08-13 17:19:40 +08:00
transition: transform 0.18s ease, filter 0.18s ease;
}
/* 选中时图片略微放大 */
.click-box-target .image-photo {
/* 让图片跟随父元素缩放,不额外放大,保留平滑过渡 */
transform: none;
transition: transform 0.18s ease, filter 0.18s ease;
filter: none;
}
</style>