2025-06-25 21:54:18 +08:00
|
|
|
<script setup>
|
|
|
|
|
import { ref, onMounted, onUnmounted, watch } from "vue";
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
stopMatch: {
|
|
|
|
|
type: Function,
|
|
|
|
|
default: () => {},
|
|
|
|
|
},
|
|
|
|
|
onComplete: {
|
|
|
|
|
type: Function,
|
|
|
|
|
default: null,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
const playerNames = [
|
|
|
|
|
"彭妮·希利",
|
|
|
|
|
"埃琳娜·奥西波娃",
|
|
|
|
|
"凯西·考夫霍尔德",
|
|
|
|
|
"起鼓相当的对手",
|
|
|
|
|
"马乌罗·内斯波利",
|
|
|
|
|
"埃琳娜·奥西波娃",
|
|
|
|
|
"凯西·考夫霍尔德",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const totalTop = ref(0);
|
|
|
|
|
const timer = ref(null);
|
|
|
|
|
const textStyles = ref([]);
|
|
|
|
|
|
|
|
|
|
const getTextStyle = (top) => {
|
|
|
|
|
const styles = [
|
|
|
|
|
{
|
|
|
|
|
color: "#fff9",
|
|
|
|
|
fontSize: "20px",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
color: "#fff",
|
|
|
|
|
fontSize: "24px",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
color: "#fed847",
|
|
|
|
|
fontSize: "30px",
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
const data = new Array(14).fill({
|
|
|
|
|
color: "#fff6",
|
|
|
|
|
fontSize: "16px",
|
|
|
|
|
});
|
|
|
|
|
const unitHeight = 100 / 7;
|
|
|
|
|
let style = {};
|
|
|
|
|
if (top >= 100 - unitHeight / 2) {
|
|
|
|
|
for (let j = 0; j < 5; j++) {
|
|
|
|
|
data[j + 1] = styles[j > 2 ? 4 - j : j];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
new Array(7).fill(1).some((_, i) => {
|
|
|
|
|
if (
|
|
|
|
|
top >= unitHeight * i - unitHeight / 2 &&
|
|
|
|
|
top < unitHeight * (i + 1) - unitHeight / 2
|
|
|
|
|
) {
|
|
|
|
|
for (let j = 0; j < 5; j++) {
|
|
|
|
|
data[7 + j + 1 - i] = styles[j > 2 ? 4 - j : j];
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
};
|
|
|
|
|
watch(
|
|
|
|
|
() => props.onComplete,
|
|
|
|
|
(newVal, oldVal) => {
|
|
|
|
|
if (newVal && !oldVal) {
|
|
|
|
|
if (timer.value) clearInterval(timer.value);
|
|
|
|
|
timer.value = setInterval(() => {
|
|
|
|
|
if (totalTop.value === 100) {
|
|
|
|
|
clearInterval(timer.value);
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
newVal();
|
2025-06-26 01:27:23 +08:00
|
|
|
}, 2000);
|
2025-06-25 21:54:18 +08:00
|
|
|
} else {
|
|
|
|
|
totalTop.value += 0.5;
|
|
|
|
|
}
|
|
|
|
|
textStyles.value = getTextStyle(totalTop.value);
|
|
|
|
|
}, 10);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
timer.value = setInterval(() => {
|
|
|
|
|
if (totalTop.value === 100) {
|
|
|
|
|
totalTop.value = 0;
|
|
|
|
|
} else {
|
2025-06-26 13:41:40 +08:00
|
|
|
totalTop.value += 2;
|
2025-06-25 21:54:18 +08:00
|
|
|
}
|
|
|
|
|
textStyles.value = getTextStyle(totalTop.value);
|
2025-06-26 13:41:40 +08:00
|
|
|
}, 40);
|
2025-06-25 21:54:18 +08:00
|
|
|
});
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
if (timer.value) clearInterval(timer.value);
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<view class="matching">
|
|
|
|
|
<image
|
|
|
|
|
src="../static/matching-bg.png"
|
|
|
|
|
mode="widthFix"
|
|
|
|
|
class="matching-bg"
|
|
|
|
|
/>
|
|
|
|
|
<view>
|
|
|
|
|
<view
|
|
|
|
|
class="player-names"
|
|
|
|
|
:style="{
|
|
|
|
|
top: `${totalTop - 100}%`,
|
|
|
|
|
}"
|
|
|
|
|
>
|
|
|
|
|
<text
|
|
|
|
|
v-for="(name, index) in playerNames"
|
|
|
|
|
:key="index"
|
|
|
|
|
:style="{
|
2025-06-26 01:27:23 +08:00
|
|
|
lineHeight: `${95 / 7}vw`,
|
2025-06-25 21:54:18 +08:00
|
|
|
...(textStyles[index] || {}),
|
|
|
|
|
}"
|
|
|
|
|
>
|
|
|
|
|
{{ name }}
|
|
|
|
|
</text>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="player-names" :style="{ top: `${totalTop}%` }">
|
|
|
|
|
<text
|
|
|
|
|
v-for="(name, index) in playerNames"
|
|
|
|
|
:key="index"
|
|
|
|
|
:style="{
|
2025-06-26 01:27:23 +08:00
|
|
|
lineHeight: `${95 / 7}vw`,
|
2025-06-25 21:54:18 +08:00
|
|
|
...(textStyles[index + 7] || {}),
|
|
|
|
|
}"
|
|
|
|
|
>
|
|
|
|
|
{{ name }}
|
|
|
|
|
</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<button hover-class="none" @click="stopMatch">取消匹配</button>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.matching {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
.matching > view {
|
|
|
|
|
width: 70vw;
|
2025-06-26 01:27:23 +08:00
|
|
|
height: 95vw;
|
2025-06-25 21:54:18 +08:00
|
|
|
overflow: hidden;
|
2025-06-26 13:41:40 +08:00
|
|
|
position: absolute;
|
|
|
|
|
top: 30.5vw;
|
2025-06-25 21:54:18 +08:00
|
|
|
}
|
|
|
|
|
.matching-bg {
|
|
|
|
|
position: absolute;
|
|
|
|
|
width: 70vw;
|
|
|
|
|
height: 102vw;
|
2025-06-26 01:27:23 +08:00
|
|
|
top: 27vw;
|
2025-06-25 21:54:18 +08:00
|
|
|
}
|
|
|
|
|
.matching > button {
|
|
|
|
|
width: 55%;
|
|
|
|
|
padding: 18px;
|
|
|
|
|
color: #000;
|
|
|
|
|
background-color: #fed847;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
border-radius: 30px;
|
2025-06-26 13:41:40 +08:00
|
|
|
position: absolute;
|
|
|
|
|
top: 142vw;
|
2025-06-25 21:54:18 +08:00
|
|
|
}
|
|
|
|
|
.player-names {
|
|
|
|
|
width: 100%;
|
2025-06-26 01:27:23 +08:00
|
|
|
height: 95vw;
|
2025-06-25 21:54:18 +08:00
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 0;
|
|
|
|
|
}
|
|
|
|
|
.player-names > text {
|
|
|
|
|
width: 100%;
|
|
|
|
|
text-align: center;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
</style>
|