Files
rsxm-master/src/views/cpp/components/pfjgfb.vue
2025-08-18 16:50:57 +08:00

138 lines
3.5 KiB
Vue

<template>
<div class="training-products-container">
<div class="products-section">
<div class="products-grid">
<div class="product-card" v-for="(item, index) in products" :key="index">
<div class="icon">
<img :src="item.icon" :alt="item.name" />
</div>
<div class="info flex">
<div class="label">{{ item.name }}</div>
<div class="value">{{ animatedValues.products[index] }}<span class="ge ml10"></span> </div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const products = ref([
{
name: '培训机构:',
count: 5,
icon: require('@/assets/images/2.png')
},
{
name: '企业:',
count: 23,
icon: require('@/assets/images/1.png')
},
{
name: '高校:',
count: 7,
icon: require('@/assets/images/3.png')
},
]);
const animatedValues = ref({
products: [0, 0, 0, 0]
});
const animateNumber = (startValue, endValue, duration, updateCallback) => {
const startTime = Date.now();
const endTime = startTime + duration;
const animate = () => {
const currentTime = Date.now();
const progress = Math.min((currentTime - startTime) / duration, 1);
const currentValue = Math.floor(startValue + (endValue - startValue) * progress);
updateCallback(currentValue);
if (progress < 1) {
requestAnimationFrame(animate);
}
};
requestAnimationFrame(animate);
};
onMounted(() => {
products.value.forEach((item, index) => {
animateNumber(0, item.count, 2000, (value) => animatedValues.value.products[index] = value);
});
});
</script>
<style lang="scss" scoped>
@mixin textColor($color1, $color2) {
background-image: linear-gradient(to top, $color1 0%, $color2 50%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.training-products-container {
padding: 0 24px;
min-height: 100vh;
color: #fff;
font-family: "YSBTH";
.products-section {
border-radius: 12px;
.products-grid {
.product-card {
border-radius: 8px;
display: flex;
align-items: center;
margin-bottom: 10px;
margin-left: 30px;
height: 180px;
&:hover {
transform: translateY(-4px);
border-color: rgba(24, 144, 255, 0.6);
box-shadow: 0 0 30px rgba(24, 144, 255, 0.25);
}
.icon {
width: 188px;
margin-right: 16px;
display: flex;
align-items: center;
justify-content: center;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.info {
display: flex;
align-items: center;
.label {
font-size: 3vw;
color: #8cc8ff;
letter-spacing: 4px;
@include textColor(#003D63,#ffffff);
margin-right: 30px;
margin-left: 30px;
}
.value {
letter-spacing: 4px;
font-size: 2.5vw;
font-weight: bold;
@include textColor(#8cc8ff,#ffffff);
}
.ge{
font-size: 2.2vw;
}
}
}
}
}
}
</style>