Files
shoot-miniprograms/src/components/Matching.vue

191 lines
3.8 KiB
Vue
Raw Normal View History

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>