添加匹配中效果

This commit is contained in:
kron
2025-06-25 21:54:18 +08:00
parent 664678cba0
commit 9090f06730
7 changed files with 353 additions and 147 deletions

190
src/components/Matching.vue Normal file
View File

@@ -0,0 +1,190 @@
<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();
}, 1000);
} else {
totalTop.value += 0.5;
}
textStyles.value = getTextStyle(totalTop.value);
}, 10);
}
}
);
onMounted(() => {
timer.value = setInterval(() => {
if (totalTop.value === 100) {
totalTop.value = 0;
} else {
totalTop.value += 0.5;
}
textStyles.value = getTextStyle(totalTop.value);
}, 10);
});
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="{
lineHeight: `${98 / 7}vw`,
...(textStyles[index] || {}),
}"
>
{{ name }}
</text>
</view>
<view class="player-names" :style="{ top: `${totalTop}%` }">
<text
v-for="(name, index) in playerNames"
:key="index"
:style="{
lineHeight: `${98 / 7}vw`,
...(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;
height: 98vw;
overflow: hidden;
position: relative;
transform: translateY(3vw);
}
.matching-bg {
position: absolute;
width: 70vw;
height: 102vw;
top: 30vw;
}
.matching > button {
width: 55%;
margin-top: 20vw;
padding: 18px;
color: #000;
background-color: #fed847;
font-size: 18px;
border-radius: 30px;
}
.player-names {
width: 100%;
height: 98vw;
display: flex;
flex-direction: column;
position: absolute;
top: 0;
transform: translateY(3vw);
}
.player-names > text {
width: 100%;
text-align: center;
transition: all 0.3s ease;
}
</style>