style: prizes移动端

This commit is contained in:
2026-03-18 14:25:49 +08:00
parent 8efe7efa71
commit 6294f18b4b
4 changed files with 271 additions and 259 deletions

View File

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -136,11 +136,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue' import { nextTick, onBeforeUnmount, onMounted, ref, inject } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { gsap } from 'gsap' import { gsap } from 'gsap'
const { t } = useI18n() const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const leftRequirment = ref([ const leftRequirment = ref([
{ {

View File

@@ -1,276 +1,287 @@
<template> <template>
<div <div
class="prizes-container container flex align-center space-between" class="prizes-container container flex align-center space-between"
ref="prizesRef" ref="prizesRef"
> :class="{ mobile: isMobile, 'flex-col': isMobile }"
<div class="left flex flex-col flex-center"> >
<div <div class="left flex flex-col flex-center">
class="title" <div class="title" ref="prizesTitleRef">
ref="prizesTitleRef" {{ $t('AwardsPage.awardPrizes') }}
> </div>
{{ $t('AwardsPage.awardPrizes') }} <!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
</div> <div class="desc" ref="prizesSubTitleRef">
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> --> {{ $t('AwardsPage.recognition') }}
<div </div>
class="desc" </div>
ref="prizesSubTitleRef" <div class="right" ref="prizesRightRef">
> <div
{{ $t('AwardsPage.recognition') }} class="prize-item flex flex-col flex-center"
</div> :class="{ smaller: item.smaller }"
</div> v-for="item in prizes"
<div :key="item.name"
class="right" >
ref="prizesRightRef" <div class="prize-money">
> {{ $t(item.money) }}
<div </div>
class="prize-item flex flex-col flex-center" <div class="prize-name">{{ $t(item.name) }}</div>
:class="{ smaller: item.smaller }" <div class="prize-desc flex flex-col flex-center">
v-for="item in prizes" <div class="desc-item" v-for="el in item.desc">
:key="item.name" {{ $t(el) }}
> </div>
<div class="prize-money"> </div>
{{ $t(item.money) }} </div>
</div> </div>
<div class="prize-name">{{ $t(item.name) }}</div> </div>
<div class="prize-desc flex flex-col flex-center">
<div
class="desc-item"
v-for="el in item.desc"
>
{{ $t(el) }}
</div>
</div>
</div>
</div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue' import { nextTick, onBeforeUnmount, onMounted, ref, inject } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { gsap } from 'gsap' import { gsap } from 'gsap'
const { t } = useI18n() const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const props = defineProps({ const props = defineProps({
isZh: { isZh: {
type: Boolean, type: Boolean,
default: false default: false
} }
}) })
const prizes = [ const prizes = [
{ {
money: 'AwardsPage.grandMoney', money: 'AwardsPage.grandMoney',
name: 'AwardsPage.grandAwards', name: 'AwardsPage.grandAwards',
desc: [ desc: ['AwardsPage.cashAward', 'AwardsPage.awardCertificate', 'AwardsPage.globalMediaExposure']
'AwardsPage.cashAward', },
'AwardsPage.awardCertificate', {
'AwardsPage.globalMediaExposure' money: 'AwardsPage.goldMoney',
] name: 'AwardsPage.goldAwards',
}, desc: ['AwardsPage.cashAward', 'AwardsPage.awardCertificate', 'AwardsPage.globalMediaExposure']
{ },
money: 'AwardsPage.goldMoney', {
name: 'AwardsPage.goldAwards', money: 'AwardsPage.silverMoney',
desc: [ name: 'AwardsPage.silverAwards',
'AwardsPage.cashAward', desc: ['AwardsPage.cashAward', 'AwardsPage.awardCertificate', 'AwardsPage.globalMediaExposure']
'AwardsPage.awardCertificate', },
'AwardsPage.globalMediaExposure' {
] money: 'AwardsPage.awardCertification',
}, name: 'AwardsPage.finalists',
{ desc: ['AwardsPage.TravelAllowance', 'AwardsPage.globalMediaExposure'],
money: 'AwardsPage.silverMoney', smaller: !props.isZh
name: 'AwardsPage.silverAwards', }
desc: [ ]
'AwardsPage.cashAward',
'AwardsPage.awardCertificate',
'AwardsPage.globalMediaExposure'
]
},
{
money: 'AwardsPage.awardCertification',
name: 'AwardsPage.finalists',
desc: ['AwardsPage.TravelAllowance', 'AwardsPage.globalMediaExposure'],
smaller: !props.isZh
}
]
const prizesRef = ref<HTMLElement | null>(null) const prizesRef = ref<HTMLElement | null>(null)
const prizesTitleRef = ref<HTMLElement | null>(null) const prizesTitleRef = ref<HTMLElement | null>(null)
const prizesSubTitleRef = ref<HTMLElement | null>(null) const prizesSubTitleRef = ref<HTMLElement | null>(null)
const prizesRightRef = ref<HTMLElement | null>(null) const prizesRightRef = ref<HTMLElement | null>(null)
const hasPlayedPrizesAnim = ref(false) const hasPlayedPrizesAnim = ref(false)
let prizesObserver: IntersectionObserver | null = null let prizesObserver: IntersectionObserver | null = null
const setupPrizesInitialState = () => { const setupPrizesInitialState = () => {
const titleEls = [prizesTitleRef.value, prizesSubTitleRef.value].filter( const titleEls = [prizesTitleRef.value, prizesSubTitleRef.value].filter(Boolean) as HTMLElement[]
Boolean if (titleEls.length) {
) as HTMLElement[] gsap.set(titleEls, {
if (titleEls.length) { opacity: 0,
gsap.set(titleEls, { scale: 0,
opacity: 0, transformOrigin: '50% 50%'
scale: 0, })
transformOrigin: '50% 50%' }
}) if (prizesRightRef.value) {
} gsap.set(prizesRightRef.value, {
if (prizesRightRef.value) { opacity: 0,
gsap.set(prizesRightRef.value, { y: 40,
'opacity': 0, scale: 1.08,
'y': 40, '--prize-row-gap': '2rem',
'scale': 1.08, '--prize-col-gap': '2rem'
'--prize-row-gap': '2rem', })
'--prize-col-gap': '2rem' }
}) }
}
}
const playPrizesAnimation = () => { const playPrizesAnimation = () => {
if (hasPlayedPrizesAnim.value) return if (hasPlayedPrizesAnim.value) return
const titleEls = [prizesTitleRef.value, prizesSubTitleRef.value].filter( const titleEls = [prizesTitleRef.value, prizesSubTitleRef.value].filter(Boolean) as HTMLElement[]
Boolean
) as HTMLElement[]
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } }) const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
if (titleEls.length) { if (titleEls.length) {
tl.to(titleEls, { tl.to(titleEls, {
opacity: 1, opacity: 1,
scale: 1, scale: 1,
duration: 0.6, duration: 0.6,
ease: 'back.out(1.6)', ease: 'back.out(1.6)',
stagger: 0.1 stagger: 0.1
}) })
} }
if (prizesRightRef.value) { if (prizesRightRef.value) {
tl.to( tl.to(
prizesRightRef.value, prizesRightRef.value,
{ {
'opacity': 1, opacity: 1,
'y': 0, y: 0,
'scale': 1, scale: 1,
'--prize-row-gap': '4.2rem', '--prize-row-gap': '4.2rem',
'--prize-col-gap': '4.4rem', '--prize-col-gap': '4.4rem',
'duration': 0.55, duration: 0.55,
'ease': 'back.out(1.4)' ease: 'back.out(1.4)'
}, },
titleEls.length ? '-=0.15' : 0 titleEls.length ? '-=0.15' : 0
) )
} }
hasPlayedPrizesAnim.value = true hasPlayedPrizesAnim.value = true
prizesObserver?.disconnect() prizesObserver?.disconnect()
} }
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
setupPrizesInitialState() setupPrizesInitialState()
if ('IntersectionObserver' in window) { if ('IntersectionObserver' in window) {
prizesObserver = new IntersectionObserver( prizesObserver = new IntersectionObserver(
entries => { (entries) => {
entries.forEach(entry => { entries.forEach((entry) => {
if (entry.isIntersecting) { if (entry.isIntersecting) {
playPrizesAnimation() playPrizesAnimation()
} }
}) })
}, },
{ threshold: 0.25 } { threshold: 0.25 }
) )
if (prizesRef.value) prizesObserver.observe(prizesRef.value) if (prizesRef.value) prizesObserver.observe(prizesRef.value)
} else { } else {
playPrizesAnimation() playPrizesAnimation()
} }
}) })
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
prizesObserver?.disconnect() prizesObserver?.disconnect()
}) })
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.prizes-container { .prizes-container {
background: url('@/assets/images/award/prizes_bg.png') no-repeat; background: url('@/assets/images/award/prizes_bg.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
padding: 0 21.4rem 0 34.2rem; padding: 0 21.4rem 0 34.2rem;
box-sizing: border-box; box-sizing: border-box;
.left { .left {
row-gap: 3.6rem; row-gap: 3.6rem;
.title { .title {
text-align: center; text-align: center;
font-family: 'PoppinsBold'; font-family: 'PoppinsBold';
font-weight: 600; font-weight: 600;
font-size: 4rem; font-size: 4rem;
color: #fff; color: #fff;
} }
.desc { .desc {
text-align: center; text-align: center;
color: #f95750; color: #f95750;
font-family: 'Poppins'; font-family: 'Poppins';
font-weight: 400; font-weight: 400;
font-size: 3rem; font-size: 3rem;
} }
} }
.right { .right {
// height: 45.4rem; // height: 45.4rem;
// padding: 4.6rem 6.1rem 4.6rem 0; // padding: 4.6rem 6.1rem 4.6rem 0;
box-sizing: border-box; box-sizing: border-box;
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr);
row-gap: var(--prize-row-gap, 4.2rem); row-gap: var(--prize-row-gap, 4.2rem);
column-gap: var(--prize-col-gap, 4.4rem); column-gap: var(--prize-col-gap, 4.4rem);
// flex: 1; // flex: 1;
.prize-item { .prize-item {
width: 35.5rem; width: 35.5rem;
height: 32.8rem; height: 32.8rem;
color: #fff; color: #fff;
padding: 4.5rem 0 4.8rem 0; padding: 4.5rem 0 4.8rem 0;
justify-content: space-between; justify-content: space-between;
background: url('@/assets/images/award/first_bg.png') no-repeat; background: url('@/assets/images/award/first_bg.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
&:nth-of-type(2) { &:nth-of-type(2) {
background: url('@/assets/images/award/second_bg.png') no-repeat; background: url('@/assets/images/award/second_bg.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
} }
&:nth-of-type(3) { &:nth-of-type(3) {
background: url('@/assets/images/award/grand_bg.png') no-repeat; background: url('@/assets/images/award/grand_bg.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
} }
&:nth-of-type(4) { &:nth-of-type(4) {
background: url('@/assets/images/award/certification_bg.png') background: url('@/assets/images/award/certification_bg.png') no-repeat;
no-repeat; background-size: 100% 100%;
background-size: 100% 100%; }
} &.smaller {
&.smaller { .prize-money {
.prize-money { font-size: 3.6rem;
font-size: 3.6rem; line-height: 3.8rem;
line-height: 3.8rem; }
} }
} .prize-money {
.prize-money { font-family: 'PoppinsBold';
font-family: 'PoppinsBold'; font-weight: bold;
font-weight: bold; font-size: 4rem;
font-size: 4rem; white-space: pre-line;
white-space: pre-line; text-align: center;
text-align: center; line-height: 7.6rem;
line-height: 7.6rem; &.smaller {
&.smaller { font-size: 3.6rem;
font-size: 3.6rem; }
} }
} .prize-name {
.prize-name { font-family: 'PoppinsMedium';
font-family: 'PoppinsMedium'; font-weight: 500;
font-weight: 500; font-size: 2.8rem;
font-size: 2.8rem; }
} .prize-desc {
.prize-desc { color: #e0e0e0;
color: #e0e0e0; font-family: 'Arial';
font-family: 'Arial'; font-weight: 400;
font-weight: 400; font-size: 2rem;
font-size: 2rem; line-height: 3rem;
line-height: 3rem; height: 8.9rem;
height: 8.9rem; }
} }
} }
} &.mobile {
} height: 102.8rem;
padding: 6rem 6.6rem 0;
background: url('@/assets/images/mobile_version_background/prizes_bg.png') no-repeat;
background-size: 100% 100%;
justify-content: flex-start;
row-gap: 6rem;
.left {
row-gap: 0.8rem;
.title {
font-size: 3.2rem;
}
.desc {
font-size: 2.4rem;
}
}
.right {
.prize-item {
width: 29.2rem;
height: 27rem;
padding: 5rem 3rem;
row-gap: 1.8rem;
&,
&.smaller .prize-money {
font-size: 2.8rem;
line-height: 1;
}
.prize-name {
font-size: 2.4rem;
}
.prize-desc {
font-size: 2rem;
line-height: 2.6rem;
}
}
}
}
}
</style> </style>