237 lines
6.3 KiB
Vue
237 lines
6.3 KiB
Vue
<template>
|
|
<view class="move-circle" :style="{ bottom: `${movebottom}rpx`, left: `${moveleft}rpx` }">
|
|
|
|
<!-- 返回 -->
|
|
<view
|
|
:class="beblue === 5 ? 'click-box-target' : 'click-box'"
|
|
@tap="onTap(5)"
|
|
@longpress="() => onLongPressStart(5)"
|
|
@touchend="onLongPressEnd"
|
|
@touchcancel="onLongPressEnd"
|
|
style="position: relative;"
|
|
>
|
|
<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>
|
|
</view>
|
|
|
|
<!-- 上 -->
|
|
<view
|
|
:class="beblue === 0 ? 'click-box-target' : 'click-box'"
|
|
@tap="onTap(0)"
|
|
@longpress="() => onLongPressStart(0)"
|
|
@touchend="onLongPressEnd"
|
|
@touchcancel="onLongPressEnd"
|
|
style="position: relative;"
|
|
>
|
|
<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" />
|
|
</view>
|
|
|
|
<!-- 确定 -->
|
|
<view
|
|
:class="beblue === 4 ? 'click-box-target' : 'click-box'"
|
|
@tap="onTap(4)"
|
|
@longpress="() => onLongPressStart(4)"
|
|
@touchend="onLongPressEnd"
|
|
@touchcancel="onLongPressEnd"
|
|
style="position: relative;"
|
|
>
|
|
<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>
|
|
</view>
|
|
|
|
<!-- 左 -->
|
|
<view
|
|
:class="beblue === 3 ? 'click-box-target' : 'click-box'"
|
|
@tap="onTap(3)"
|
|
@longpress="() => onLongPressStart(3)"
|
|
@touchend="onLongPressEnd"
|
|
@touchcancel="onLongPressEnd"
|
|
style="position: relative;"
|
|
>
|
|
<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" />
|
|
</view>
|
|
|
|
<!-- 下 -->
|
|
<view
|
|
:class="beblue === 2 ? 'click-box-target' : 'click-box'"
|
|
@tap="onTap(2)"
|
|
@longpress="() => onLongPressStart(2)"
|
|
@touchend="onLongPressEnd"
|
|
@touchcancel="onLongPressEnd"
|
|
style="position: relative;"
|
|
>
|
|
<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" />
|
|
</view>
|
|
|
|
<!-- 右 -->
|
|
<view
|
|
:class="beblue === 1 ? 'click-box-target' : 'click-box'"
|
|
@tap="onTap(1)"
|
|
@longpress="() => onLongPressStart(1)"
|
|
@touchend="onLongPressEnd"
|
|
@touchcancel="onLongPressEnd"
|
|
style="position: relative;"
|
|
>
|
|
<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" />
|
|
</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 longPressTimer : ReturnType<typeof setTimeout> | null = null
|
|
let isLongPress = false
|
|
const beblue = ref<number>(-1)
|
|
let activeLongPressDir : number | null = null
|
|
|
|
const props = defineProps({
|
|
movebottom: { type: Number, default: 30 },
|
|
moveleft: { type: Number, default: 10 },
|
|
leftbuttonname: { type: String, default: "返回" },
|
|
rightbuttonname: { type: String, default: "确定" },
|
|
})
|
|
|
|
function clearClickResetTimer() {
|
|
if (clickResetTimer) {
|
|
clearTimeout(clickResetTimer)
|
|
clickResetTimer = null
|
|
}
|
|
}
|
|
|
|
function clearLongPressTimer() {
|
|
if (longPressTimer) {
|
|
clearTimeout(longPressTimer)
|
|
longPressTimer = null
|
|
}
|
|
isLongPress = false
|
|
activeLongPressDir = null
|
|
}
|
|
|
|
// 单击(或短按)
|
|
function onTap(dir : number) {
|
|
clearLongPressTimer()
|
|
clearClickResetTimer()
|
|
|
|
beblue.value = dir
|
|
emit('movecard', dir)
|
|
|
|
clickResetTimer = setTimeout(() => {
|
|
beblue.value = -1
|
|
clickResetTimer = null
|
|
}, 500)
|
|
}
|
|
|
|
// 长按开始
|
|
function onLongPressStart(dir : number) {
|
|
clearClickResetTimer()
|
|
clearLongPressTimer()
|
|
|
|
beblue.value = dir
|
|
emit('movecard', dir)
|
|
|
|
activeLongPressDir = dir
|
|
isLongPress = true
|
|
|
|
function loop() {
|
|
if (!isLongPress || activeLongPressDir === null) return
|
|
// emit('movecard', activeLongPressDir)
|
|
longPressTimer = setTimeout(loop, 500)
|
|
}
|
|
longPressTimer = setTimeout(loop, 500)
|
|
}
|
|
|
|
// 长按结束
|
|
function onLongPressEnd() {
|
|
if (!isLongPress) return
|
|
clearLongPressTimer()
|
|
|
|
clearClickResetTimer()
|
|
clickResetTimer = setTimeout(() => {
|
|
beblue.value = -1
|
|
clickResetTimer = null
|
|
}, 500)
|
|
}
|
|
|
|
onBeforeUnmount(() => {
|
|
clearClickResetTimer()
|
|
clearLongPressTimer()
|
|
})
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.move-circle {
|
|
position: absolute;
|
|
bottom: 0rpx;
|
|
left: 0rpx;
|
|
width: 500rpx;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
z-index: 99;
|
|
touch-action: none;
|
|
}
|
|
|
|
.click-box,
|
|
.click-box-target {
|
|
width: 150rpx;
|
|
height: 137rpx;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-size: 28rpx;
|
|
transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.25s ease;
|
|
-webkit-tap-highlight-color: transparent;
|
|
margin-bottom: 10rpx;
|
|
}
|
|
|
|
.click-box {
|
|
color: #888d99;
|
|
}
|
|
|
|
.click-box-target {
|
|
color: transparent;
|
|
animation: scalePulse 360ms cubic-bezier(.2, .8, .2, 1);
|
|
transform-origin: center center;
|
|
}
|
|
|
|
@keyframes scalePulse {
|
|
0% { transform: scale(1); }
|
|
25% { transform: scale(0.94); }
|
|
65% { transform: scale(1.08); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
.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 {
|
|
width: 25%;
|
|
height: 25%;
|
|
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>
|