feat: 平板端适配

This commit is contained in:
2026-03-23 11:09:13 +08:00
parent 6a08f2cede
commit 982b7308e8
12 changed files with 114 additions and 48 deletions

View File

@@ -3,7 +3,7 @@
class="apply-container flex flex-col"
id="apply"
ref="applyRef"
:class="{ mobile: isMobile }"
:class="{ mobile: isMobile && !isPad, 'is-pad': isPad }"
>
<div class="title animation-element" ref="applyTitleRef">
{{ $t('AwardsPage.howToApply') }}
@@ -12,7 +12,7 @@
{{ $t('AwardsPage.stepByStep') }}
</div>
<div class="requirments-list flex flex-col" ref="reqListRef">
<div class="top flex" :class="{ 'flex-col': isMobile }">
<div class="top flex" :class="{ 'flex-col': isMobile && !isPad }">
<div
class="item-box animation-element"
v-for="(item, index) in leftRequirment"
@@ -27,7 +27,10 @@
<div class="item-header flex flex-center">
<div class="item-title">{{ $t(item.type) }}</div>
</div>
<div class="context-container flex flex-center" :class="{ 'flex-col': isMobile }">
<div
class="context-container flex flex-center"
:class="{ 'flex-col': isMobile && !isPad }"
>
<div class="context" v-for="el in item.desc">
{{ $t(el) }}
</div>
@@ -42,10 +45,10 @@
</div>
</div>
</div>
<div class="bottom flex" :class="{ 'flex-col': isMobile }">
<div class="bottom flex" :class="{ 'flex-col': isMobile && !isPad }">
<div class="step-3 flex flex-col animation-element" ref="step3Ref">
<div class="header">{{ $t('AwardsPage.step3Title') }}</div>
<div class="content flex" :class="{ 'flex-col': isMobile }">
<div class="content flex" :class="{ 'flex-col': isMobile && !isPad }">
<div class="content-left flex flex-col space-between">
<div class="content-item">
<div class="item-header flex align-center">
@@ -67,7 +70,7 @@
</ul>
</div>
</div>
<div class="content-item" v-if="!isMobile">
<div class="content-item" v-if="!(isMobile && !isPad)">
<div class="item-header flex align-center">
<div class="point"></div>
<div>{{ $t('AwardsPage.fileName') }}</div>
@@ -108,7 +111,7 @@
</ul>
</div>
</div>
<div class="content-item file" v-if="isMobile">
<div class="content-item file" v-if="isMobile && !isPad">
<div class="item-header flex align-center">
<div class="point"></div>
<div>{{ $t('AwardsPage.fileName') }}</div>
@@ -156,7 +159,7 @@ import { gsap } from 'gsap'
const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const isPad = inject<boolean>('isPad')
const leftRequirment = ref([
{
type: 'AwardsPage.step1Title',
@@ -456,6 +459,7 @@ ul {
font-weight: 400;
font-size: 2.4rem;
color: #585858;
white-space: pre-line;
&.indent {
padding-left: 3.8rem;
line-height: 3rem;
@@ -473,12 +477,11 @@ ul {
line-height: 3rem;
row-gap: 3rem;
.desc-lists {
/* 使用自定义方块代替浏览器 marker保证大小为 1rem 并与文字垂直居中 */
padding-left: 0;
list-style: none;
li {
list-style: none;
/* 使内容对齐到首行顶部,方块通过 margin-top 调整到首行中间 */
white-space: pre-line;
display: flex;
align-items: flex-start;
gap: 1rem;
@@ -486,13 +489,11 @@ ul {
margin: 0.4rem 0;
&::before {
content: '';
/* 固定为 1rem 方块 */
width: 0.5rem;
height: 0.5rem;
background-color: #585858;
flex: 0 0 0.5rem;
border-radius: 0;
/* 让方块垂直居中于第一行文字:(line-height - square)/2 */
margin-top: calc((var(--desc-line-height, 3rem) - 1rem) / 2);
}
}
@@ -637,5 +638,25 @@ ul {
}
}
}
&.is-pad {
height: auto;
.top {
height: auto;
}
.bottom {
height: auto;
flex-direction: column;
.content-item {
height: auto;
}
.step-4 {
margin-top: 4rem;
width: 100%;
.desc-lists li{
white-space: initial !important;
}
}
}
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="bloom flex flex-col align-center" :class="{ mobile: isMobile }">
<div class="bloom flex flex-col align-center" :class="{ mobile: isMobile, pad: isPad }">
<div class="title" ref="titleRef">
{{ $t('AwardsPage.bloomYourCreativity') }}
</div>
@@ -27,6 +27,7 @@
</span>
{{ $t('AwardsPage.bloomText.desc1.regular5') }}
</p>
<!-- <p class="section-1 pad" v-show="isPad" v-html="padSection1"></p> -->
<p class="section-2">
{{ $t('AwardsPage.bloomText.desc2.regular1') }}
<span class="arial-bold">
@@ -45,11 +46,16 @@ import { gsap } from 'gsap'
const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const isPad = inject<boolean>('isPad')
const titleRef = ref<HTMLElement | null>(null)
const subtitleRef = ref<HTMLElement | null>(null)
const textRef = ref<HTMLElement | null>(null)
// const padSection1 = computed(() => {
// return t('AwardsPage.bloomDesc1')
// })
const hasPlayedBloomAnim = ref(false)
let bloomObserver: IntersectionObserver | null = null
@@ -149,8 +155,8 @@ p {
margin: 0;
padding: 0;
}
.arial-bold {
font-family: 'ArialBold';
:deep(.arial-bold) {
font-family: 'ArialBold', Arial, sans-serif;
font-weight: 700;
}
.bloom {
@@ -191,7 +197,6 @@ p {
&.mobile {
background: url('@/assets/images/mobile_version_background/bloom_bg.png') no-repeat;
background-size: 100% 100%;
// height: 83.1rem;
height: 110vw;
padding-top: 6rem;
.title {
@@ -203,11 +208,22 @@ p {
margin-bottom: 6.2rem;
}
.desc {
// padding: 0 6.5rem 0 6.7rem;
padding: 0 8.5vw;
font-size: 2rem;
line-height: 3rem;
}
}
&.pad {
height: 84.6vw;
background: url('@/assets/images/pad_version/bloom_bg.png') no-repeat;
background-size: 100% 100%;
.arial-bold {
font-family: 'ArialBold';
font-weight: 700;
}
.desc {
// font-size: 2.4rem;
}
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="judges-container flex flex-col align-center" :class="{ mobile: isMobile }">
<div class="judges-container flex flex-col align-center" :class="{ mobile: isMobile && !isPad }">
<div class="title" ref="judgesTitleRef">{{ $t('AwardsPage.panelOfJudges') }}</div>
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
<div class="sub-title" ref="judgesSubTitleRef">{{ $t('AwardsPage.expertise') }}</div>
@@ -30,6 +30,7 @@ import desmond from '@/assets/images/award/desmond.png'
const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const isPad = inject<boolean>('isPad')
const judgements = [
{
picture: jae,

View File

@@ -2,7 +2,7 @@
<div
class="prizes-container container flex align-center space-between"
ref="prizesRef"
:class="{ mobile: isMobile, 'flex-col': isMobile }"
:class="{ mobile: isMobile && !isPad, 'flex-col': isMobile && !isPad, 'is-pad': isPad }"
>
<div class="left flex flex-col flex-center">
<div class="title" ref="prizesTitleRef">
@@ -41,6 +41,7 @@ import { gsap } from 'gsap'
const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const isPad = inject<boolean>('isPad')
const props = defineProps({
isZh: {
@@ -283,5 +284,12 @@ onBeforeUnmount(() => {
}
}
}
&.is-pad {
background: url('@/assets/images/pad_version/prizes-bg.png') no-repeat;
background-size: 100% 100%;
padding: 0 6rem;
justify-content: center;
column-gap: 10rem;
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="blocks-list flex" ref="root" :class="{ 'in-view': inView }">
<div class="blocks-list flex" ref="root" :class="{ 'in-view': inView, mobile: isMobile }">
<div
class="block-item flex flex-col flex-center"
v-for="(item, idx) in blocksList"
@@ -14,11 +14,11 @@
</template>
<script setup lang="ts">
import { computed, ref, onMounted, onUnmounted } from 'vue'
import { computed, ref, onMounted, onUnmounted, inject } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const isMobile = inject('isMobile')
const blocksList = ref([
{
number: 'AwardsPage.totalCashPrizes',
@@ -151,7 +151,7 @@ onUnmounted(() => {
}
/* 移动端 <= 1200px 四宫格布局 */
@media (max-width: 1200px) {
.mobile {
.blocks-list {
height: auto;
flex-wrap: wrap;

View File

@@ -2,17 +2,13 @@
<div
ref="containerRef"
class="timeline-container container flex flex-col align-center"
:class="{ mobile: isMobileOrNarrow, vertical: isMobile }"
:class="{ mobile: isMobile && !isPad, vertical: isMobile && !isPad ,'is-pad': isPad}"
>
<div class="timeline-title">{{ $t('AwardsPage.competitionTimeline') }}</div>
<div class="desc">{{ $t('AwardsPage.shapingTheFuture') }}</div>
<!-- 纵向时间线移动端或宽度 <= 1200px -->
<div
v-if="isMobile"
class="timeline-point timeline-vertical flex flex-col"
ref="timelineRef"
>
<!-- 纵向时间线移动端排除平板 -->
<div v-if="isMobile && !isPad" class="timeline-point timeline-vertical flex flex-col" ref="timelineRef">
<div class="vertical-line"></div>
<div v-for="(item, index) in points" :key="'vertical-' + item.time" class="vertical-item">
<div class="vertical-node">
@@ -71,9 +67,10 @@ import { gsap } from 'gsap'
const { t } = useI18n()
const isMobile = inject<boolean>('isMobile')
const isPad = inject<boolean>('isPad')
const windowWidth = ref(typeof window !== 'undefined' ? window.innerWidth : 1201)
const isMobileOrNarrow = computed(() => isMobile.value)
const isMobileOrNarrow = computed(() => isMobile.value && !isPad.value)
const updateWindowWidth = () => {
windowWidth.value = window.innerWidth
@@ -122,7 +119,7 @@ const playAnimation = () => {
const subtitle = containerRef.value.querySelector('.desc')
const timeline = containerRef.value.querySelector('.timeline-point')
const line = containerRef.value.querySelector(
isMobile.value ? '.vertical-line' : '.timeline-line'
isMobile.value && !isPad.value ? '.vertical-line' : '.timeline-line'
)
const tl = gsap.timeline()
@@ -130,7 +127,7 @@ const playAnimation = () => {
// 整体 timeline 的裁剪展开(仅横向使用)
// 纵向时跳过裁剪动画,改用每个 item 从上方落下的动画
if (timeline && !isMobile.value) {
if (timeline && !(isMobile.value && !isPad.value)) {
tl.fromTo(
timeline,
{
@@ -148,7 +145,7 @@ const playAnimation = () => {
// 线条动画:横向 scaleX纵向 scaleY
// 纵向时线条与 item 动画同步进行
if (line) {
if (isMobile.value) {
if (isMobile.value && !isPad.value) {
tl.from(
line,
{
@@ -191,11 +188,11 @@ const playAnimation = () => {
// 行内内容:桌面端用 .grid-cell纵向用 .vertical-item
// 纵向时,每个 item 从上方落下 + 渐显
const textItems = isMobile.value
const textItems = isMobile.value && !isPad.value
? containerRef.value.querySelectorAll('.vertical-item')
: containerRef.value.querySelectorAll('.grid-cell')
if (textItems && textItems.length) {
if (isMobile.value) {
if (isMobile.value && !isPad.value) {
// 纵向:每个 item 从上方落下 + 渐显
tl.from(
textItems,
@@ -510,5 +507,9 @@ onBeforeUnmount(() => {
}
}
}
&.is-pad {
background: url('@/assets/images/pad_version/timeline_bg.png') no-repeat;
background-size: 100% 100%;
}
}
</style>

View File

@@ -29,7 +29,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, provide } from 'vue'
import { ref, computed, onMounted, provide,onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import JudgesSection from './components/JudgesSection.vue'
@@ -50,10 +50,26 @@ const { locale } = useI18n()
provide('isMobile', isMobile)
const isPad = ref(false)
provide('isPad', isPad)
const checkIsPad = () => {
const ua = navigator.userAgent.toLowerCase()
const padRegex = /ipad|tablet|playbook|silk/i
const isPadUA = padRegex.test(ua)
const isPadWidth = window.innerWidth > 768 && window.innerWidth <= 1200
isPad.value = isPadUA || isPadWidth
}
onMounted(() => {
checkIsPad()
window.addEventListener('resize', checkIsPad)
router.replace('/')
})
onUnmounted(() => {
window.removeEventListener('resize', checkIsPad)
})
const isZh = computed(() => {
return locale.value === 'CHINESE_SIMPLIFIED'
})
@@ -61,12 +77,10 @@ const isZh = computed(() => {
const bannerUrl = computed(() => {
let url = null
if (isMobile.value) {
console.log('移动端-----------')
url = isZh.value ? bannerZhMobile : bannerMobile
} else {
url = isZh.value ? bannerZh : banner
}
console.log('url-----------', url)
return url
})
@@ -147,9 +161,11 @@ const handleSubmitApplication = () => {
.banner.mobile {
height: auto;
.submit-btn {
top: 48%;
top: 52%;
left: 8%;
width: 48rem;
width: 41rem;
font-size: 2.4rem;
column-gap: 1rem;
.ddl {
white-space: pre-line;
text-align: left;