1247 lines
31 KiB
Vue
1247 lines
31 KiB
Vue
<template>
|
||
<div class="page-container">
|
||
<header className="header flex items-center justify-between">
|
||
<div class="logo">
|
||
<img src="@/assets/image/logo.png" alt="logo" />
|
||
</div>
|
||
<div class="tabs">
|
||
<div
|
||
class="tab-item"
|
||
:class="{ active: currentTab === 'home' }"
|
||
@click="handleTabClick('home')"
|
||
>
|
||
{{ t("home.nav.home") }}
|
||
</div>
|
||
<div
|
||
class="tab-item"
|
||
:class="{ active: currentTab === 'companyprofil' }"
|
||
@click="handleTabClick('companyprofil')"
|
||
>
|
||
{{ t("home.nav.company") }}
|
||
</div>
|
||
<div
|
||
class="tab-item"
|
||
:class="{ active: currentTab === 'business' }"
|
||
@click="handleTabClick('business')"
|
||
>
|
||
{{ t("home.nav.business") }}
|
||
</div>
|
||
</div>
|
||
</header>
|
||
<main ref="main">
|
||
<div class="scroll-down" :class="{ hide: !scrollDownVisible }">
|
||
{{ t("home.scroll.tip") }}
|
||
</div>
|
||
<section className="panel first-panel">
|
||
<n-carousel autoplay :interval="5000" class="no-hover">
|
||
<img
|
||
class="carousel-img"
|
||
src="@/assets/image/home/375/zh/carousel-1.png"
|
||
/>
|
||
<img
|
||
class="carousel-img"
|
||
src="@/assets/image/home/375/zh/carousel-2.png"
|
||
/>
|
||
<img
|
||
class="carousel-img"
|
||
src="@/assets/image/home/375/zh/carousel-3.png"
|
||
/>
|
||
<img
|
||
class="carousel-img"
|
||
src="@/assets/image/home/375/zh/carousel-4.png"
|
||
/>
|
||
</n-carousel>
|
||
</section>
|
||
|
||
<section
|
||
className="panel"
|
||
style="background-color: rgba(248, 249, 255, 1)"
|
||
>
|
||
<n-divider class="divider1" vertical />
|
||
<div class="divider2" style=""></div>
|
||
<div class="divider3" style=""></div>
|
||
<div class="divider4" style=""></div>
|
||
<n-divider class="divider5" vertical />
|
||
<div class="parallax-bg" style="margin-top: 50px">
|
||
<img
|
||
ref="secondImage"
|
||
class="second-image"
|
||
src="@/assets/image/home/375/bg-1.png"
|
||
/>
|
||
</div>
|
||
<div class="content">
|
||
<div
|
||
class="text-[#10253E] text-[123px] leading-[164px] font-semibold"
|
||
>
|
||
{{ t("home.section2.title1") }}
|
||
</div>
|
||
<div
|
||
class="text-[#10253E] text-[123px] leading-[164px] font-semibold"
|
||
>
|
||
{{ t("home.section2.title2") }}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section className="panel" style="background-color: #fff">
|
||
<n-divider class="divider1" vertical />
|
||
<div class="divider2" style=""></div>
|
||
<div class="divider3" style=""></div>
|
||
<div class="divider4" style=""></div>
|
||
<n-divider class="divider5" vertical />
|
||
<div class="parallax-bg" style="margin-top: 70px"></div>
|
||
<div class="content3 mt-[348px]">
|
||
<div class="text-[#8B59F7] text-[72px]">
|
||
{{ t("home.section3.label") }}
|
||
</div>
|
||
<div class="text-[#10253E] text-[113pxpx] mt-[43px]">FiEE</div>
|
||
<div class="text-[#455363] text-[72px] mt-[78px] pr-[139px]">
|
||
{{ t("home.section3.desc") }}
|
||
</div>
|
||
</div>
|
||
<div
|
||
class="mt-[140px] mb-[175px] carousel-container px-[80px] py-[40px]"
|
||
>
|
||
<div ref="carouselTrack" class="carousel-track">
|
||
<div
|
||
v-for="(item, idx) in getVisibleItems()"
|
||
:key="idx"
|
||
class="carousel-item"
|
||
>
|
||
<img class="carousel-image" :src="item.imgUrl" />
|
||
<div class="carousel-title">
|
||
<div>{{ item.title }}</div>
|
||
</div>
|
||
<div class="carousel-subtitle">
|
||
<div>{{ item.subTitle }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section className="panel" style="background-color: #f8f9ff">
|
||
<n-divider class="divider1" vertical />
|
||
<div class="divider2" style=""></div>
|
||
<div class="divider3" style=""></div>
|
||
<div class="divider4" style=""></div>
|
||
<n-divider class="divider5" vertical />
|
||
<div class="parallax-bg"></div>
|
||
<div class="content4 mt-[408px]">
|
||
<div class="text-[#8B59F7] text-[72px]">
|
||
{{ t("home.section4.label") }}
|
||
</div>
|
||
<div class="text-[#10253E] text-[113pxpx] mt-[43px]">
|
||
<div>多元业务协同</div>
|
||
<div>推动文艺影响力腾飞</div>
|
||
</div>
|
||
<div
|
||
class="text-[#455363] text-[72px] mt-[78px] leading-[60px] pr-[139px]"
|
||
>
|
||
{{ t("home.section4.desc") }}
|
||
</div>
|
||
<div class="container">
|
||
<div class="mt-[493px]">
|
||
<div class="card">
|
||
<img
|
||
src="@/assets/image/home/375/imageShow-1.png"
|
||
alt="Image 1"
|
||
/>
|
||
<div class="js-detail font-bold">
|
||
{{ t("home.section4.cards1.title") }}
|
||
<div class="text-[#455363] text-[72px] font-normal">
|
||
{{ t("home.section4.cards1.desc") }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<img
|
||
src="@/assets/image/home/375/imageShow-3.png"
|
||
alt="Image 3"
|
||
/>
|
||
<div class="js-detail font-bold">
|
||
{{ t("home.section4.cards3.title") }}
|
||
<div class="text-[#455363] text-[72px] font-normal">
|
||
{{ t("home.section4.cards3.desc") }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="right mt-[215px]">
|
||
<div class="card">
|
||
<img
|
||
src="@/assets/image/home/375/imageShow-2.png"
|
||
alt="Image 2"
|
||
/>
|
||
<div class="js-detail font-bold">
|
||
{{ t("home.section4.cards2.title") }}
|
||
<div class="text-[#455363] text-[72px] font-normal">
|
||
{{ t("home.section4.cards2.desc") }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<img
|
||
src="@/assets/image/home/375/imageShow-4.png"
|
||
alt="Image 4"
|
||
/>
|
||
<div class="js-detail font-bold">
|
||
{{ t("home.section4.cards4.title") }}
|
||
<div class="text-[#455363] text-[72px] font-normal">
|
||
{{ t("home.section4.cards4.desc") }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
<footer>
|
||
<div style="background: #fff" className="flex flex-wrap justify-center">
|
||
<img
|
||
class="w-[891px] h-[87px] mt-[61px] mb-[56px]"
|
||
src="@/assets/image/image-footer.png"
|
||
alt="logo"
|
||
/>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { NCarousel, NDivider, NImage } from "naive-ui";
|
||
import { onUnmounted, ref, watch, onMounted, reactive, nextTick } from "vue";
|
||
import gsap from "gsap";
|
||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||
import { useHome } from "@/store/home/index.js";
|
||
import { useTransitionComposable } from "@/composables/transition-composable";
|
||
import { useI18n } from "vue-i18n";
|
||
import { useRouter } from "vue-router";
|
||
|
||
const router = useRouter();
|
||
const { transitionState } = useTransitionComposable();
|
||
const main = ref();
|
||
const secondImage = ref(null);
|
||
let scrollTween;
|
||
let ctx;
|
||
const { currentTab } = useHome();
|
||
let isScrolling = false; // 添加滚动状态标记
|
||
const scrollThreshold = 50; // 添加滚动阈值
|
||
let lastScrollTime = 0; // 添加最后滚动时间记录
|
||
const scrollDownVisible = ref(true);
|
||
const { t } = useI18n();
|
||
|
||
// 导入图片
|
||
import imageshow3 from "@/assets/image/businessintroduction/375/imageshow-3.png";
|
||
import imageshow4 from "@/assets/image/businessintroduction/375/imageshow-4.png";
|
||
import imageshow5 from "@/assets/image/businessintroduction/375/imageshow-5.png";
|
||
|
||
const state = reactive({
|
||
marqueeArr: [
|
||
{
|
||
title: "2025年",
|
||
subTitle:
|
||
"自媒体平台曝光量突破 5 亿+,通过多平台联动、创意内容营销,提升品牌与创作者曝光度。",
|
||
imgUrl: imageshow3, // 使用导入的图片
|
||
},
|
||
{
|
||
title: "2026年",
|
||
subTitle: "曝光量达 10 亿 +,深化品牌传播,吸引更多潜在用户与合作伙伴。",
|
||
imgUrl: imageshow4, // 使用导入的图片
|
||
},
|
||
{
|
||
title: "2027年",
|
||
subTitle:
|
||
"实现 50 亿 + 跨次元突破,打破行业与文化界限,全方位提升品牌国际影响力,推动文化艺术与科技深度交融 ,塑造行业发展新潮流。",
|
||
imgUrl: imageshow5, // 使用导入的图片
|
||
},
|
||
],
|
||
});
|
||
|
||
const handleTabClick = (tab) => {
|
||
currentTab.value = tab;
|
||
router.push("/" + tab);
|
||
};
|
||
|
||
const goToSection = (i) => {
|
||
if (scrollTween) {
|
||
scrollTween.kill();
|
||
}
|
||
|
||
// 防止频繁触发
|
||
const now = Date.now();
|
||
if (now - lastScrollTime < 500) return; // 500ms 内不重复触发
|
||
lastScrollTime = now;
|
||
|
||
isScrolling = true;
|
||
scrollTween = gsap.to(window, {
|
||
scrollTo: { y: i * window.innerHeight, autoKill: false },
|
||
duration: 0.8, // 增加动画时间使其更平滑
|
||
ease: "power2.inOut",
|
||
onComplete: () => {
|
||
scrollTween = null;
|
||
isScrolling = false;
|
||
},
|
||
overwrite: true,
|
||
});
|
||
};
|
||
|
||
// 修改handleWheel函数
|
||
const handleWheel = (e) => {
|
||
if (isScrolling) {
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
|
||
const delta = e.deltaY;
|
||
const currentSection = Math.round(window.scrollY / window.innerHeight);
|
||
const lastPanel = document.querySelector(".panel:last-child");
|
||
const isInLastPanel = currentSection === 3;
|
||
|
||
// 在最后一个panel时允许自然滚动
|
||
if (isInLastPanel && lastPanel.scrollHeight > window.innerHeight) {
|
||
// 检查是否在panel顶部且向上滚动,或在底部且向下滚动
|
||
if (
|
||
(lastPanel.scrollTop === 0 && delta < 0) ||
|
||
(lastPanel.scrollTop + lastPanel.clientHeight >= lastPanel.scrollHeight &&
|
||
delta > 0)
|
||
) {
|
||
// 只有在这些边界条件下才触发页面切换
|
||
if (Math.abs(delta) > scrollThreshold) {
|
||
if (delta > 0 && currentSection < 3) {
|
||
goToSection(currentSection + 1);
|
||
} else if (delta < 0 && currentSection > 0) {
|
||
goToSection(currentSection - 1);
|
||
}
|
||
}
|
||
}
|
||
return; // 其他情况允许自然滚动
|
||
}
|
||
|
||
// 非最后一个panel的处理保持不变
|
||
if (Math.abs(delta) > scrollThreshold) {
|
||
if (delta > 0 && currentSection < 3) {
|
||
goToSection(currentSection + 1);
|
||
} else if (delta < 0 && currentSection > 0) {
|
||
goToSection(currentSection - 1);
|
||
}
|
||
}
|
||
};
|
||
|
||
// 监听滚轮事件
|
||
onMounted(() => {
|
||
window.addEventListener("wheel", handleWheel, { passive: false });
|
||
// 初始化轮播动画
|
||
nextTick(() => {
|
||
if (carouselTrack.value) {
|
||
const firstItem = carouselTrack.value.querySelector(".carousel-item");
|
||
if (!firstItem) return;
|
||
|
||
const itemWidth = firstItem.offsetWidth;
|
||
const itemMargin = parseInt(
|
||
window.getComputedStyle(firstItem).marginRight
|
||
);
|
||
const slideWidth = itemWidth + itemMargin;
|
||
const totalWidth = slideWidth * state.marqueeArr.length;
|
||
|
||
// 创建无限滚动动画
|
||
carouselAnimation = gsap.to(carouselTrack.value, {
|
||
x: -totalWidth,
|
||
duration: 20,
|
||
ease: "none",
|
||
repeat: -1,
|
||
onRepeat: () => {
|
||
gsap.set(carouselTrack.value, { x: 0 });
|
||
},
|
||
});
|
||
}
|
||
});
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
window.removeEventListener("wheel", handleWheel);
|
||
ctx?.revert();
|
||
ScrollTrigger.killAll();
|
||
if (carouselAnimation) {
|
||
carouselAnimation.kill();
|
||
}
|
||
});
|
||
|
||
watch(
|
||
[() => transitionState.transitionComplete, main],
|
||
(newValue) => {
|
||
if (newValue && main.value) {
|
||
ctx = gsap.context((self) => {
|
||
const panels = self.selector(".panel");
|
||
|
||
// 为每个面板创建滚动触发器
|
||
panels.forEach((panel, i) => {
|
||
ScrollTrigger.create({
|
||
trigger: panel,
|
||
start: "top center",
|
||
end: "bottom center",
|
||
onToggle: (self) => {
|
||
if (self.isActive && !isScrolling) {
|
||
goToSection(i);
|
||
}
|
||
},
|
||
preventOverlaps: true,
|
||
});
|
||
});
|
||
|
||
// 移除之前的渐入动画代码
|
||
panels.forEach((panel, i) => {
|
||
// 背景视差
|
||
const bg = panel.querySelector(".parallax-bg");
|
||
if (bg) {
|
||
gsap.to(bg, {
|
||
yPercent: 30,
|
||
ease: "none",
|
||
scrollTrigger: {
|
||
trigger: panel,
|
||
start: "top bottom",
|
||
end: "bottom top",
|
||
scrub: true,
|
||
},
|
||
});
|
||
}
|
||
|
||
// 内容视差
|
||
const content = panel.querySelector(".content");
|
||
if (content) {
|
||
gsap.from(content, {
|
||
yPercent: 50,
|
||
opacity: 0,
|
||
scrollTrigger: {
|
||
trigger: panel,
|
||
start: "top center",
|
||
end: "center center",
|
||
scrub: true,
|
||
},
|
||
});
|
||
}
|
||
});
|
||
|
||
// 修改第二个面板的动画配置
|
||
ScrollTrigger.create({
|
||
trigger: panels[1],
|
||
start: "top 60%", // 调整为更晚的触发时机
|
||
end: "bottom 40%", // 调整离开时机
|
||
onEnter: () => {
|
||
// 进入第二幕时
|
||
gsap.to(secondImage.value, {
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 1.2,
|
||
ease: "power2.out",
|
||
});
|
||
},
|
||
onLeave: () => {
|
||
// 离开第二幕时(向下滚动)
|
||
gsap.to(secondImage.value, {
|
||
opacity: 0,
|
||
y: -50,
|
||
duration: 0.5, // 加快渐出速度
|
||
ease: "power1.in", // 使用更快的缓动函数
|
||
});
|
||
},
|
||
onEnterBack: () => {
|
||
// 重新进入第二幕时(向上滚动)
|
||
gsap.to(secondImage.value, {
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 1.2,
|
||
ease: "power2.out",
|
||
});
|
||
},
|
||
onLeaveBack: () => {
|
||
// 返回第一幕时(向上滚动)
|
||
gsap.to(secondImage.value, {
|
||
opacity: 0,
|
||
y: 50,
|
||
duration: 0.5, // 加快渐出速度
|
||
ease: "power1.in", // 使用更快的缓动函数
|
||
});
|
||
},
|
||
});
|
||
|
||
// 修改第三幕的ScrollTrigger配置
|
||
ScrollTrigger.create({
|
||
trigger: panels[2],
|
||
start: "top 60%", // 提前触发
|
||
end: "bottom center",
|
||
onEnter: () => {
|
||
// 初始状态设置
|
||
gsap.set(".content3", {
|
||
opacity: 1, // 容器始终保持可见
|
||
y: 0,
|
||
});
|
||
|
||
gsap.set(
|
||
[
|
||
".content3 > div:nth-child(1)",
|
||
".content3 > div:nth-child(2)",
|
||
".content3 > div:nth-child(3)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: 50,
|
||
}
|
||
);
|
||
|
||
const tl = gsap.timeline({
|
||
defaults: {
|
||
duration: 0.8,
|
||
ease: "power2.out",
|
||
},
|
||
});
|
||
|
||
tl.to(".content3 > div:nth-child(1)", {
|
||
opacity: 1,
|
||
y: 0,
|
||
})
|
||
.to(
|
||
".content3 > div:nth-child(2)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.6"
|
||
)
|
||
.to(
|
||
".content3 > div:nth-child(3)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.6"
|
||
);
|
||
},
|
||
onLeave: () => {
|
||
const tl = gsap.timeline({
|
||
defaults: {
|
||
duration: 0.3,
|
||
ease: "power2.in",
|
||
},
|
||
});
|
||
|
||
tl.to(
|
||
[
|
||
".content3 > div:nth-child(3)",
|
||
".content3 > div:nth-child(2)",
|
||
".content3 > div:nth-child(1)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: -30,
|
||
stagger: 0.1,
|
||
}
|
||
);
|
||
},
|
||
onEnterBack: () => {
|
||
gsap.set(".content3", {
|
||
opacity: 1,
|
||
y: 0,
|
||
});
|
||
|
||
gsap.set(
|
||
[
|
||
".content3 > div:nth-child(1)",
|
||
".content3 > div:nth-child(2)",
|
||
".content3 > div:nth-child(3)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: -50,
|
||
}
|
||
);
|
||
|
||
const tl = gsap.timeline({
|
||
defaults: {
|
||
duration: 0.8,
|
||
ease: "power2.out",
|
||
},
|
||
});
|
||
|
||
tl.to(".content3 > div:nth-child(1)", {
|
||
opacity: 1,
|
||
y: 0,
|
||
})
|
||
.to(
|
||
".content3 > div:nth-child(2)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.6"
|
||
)
|
||
.to(
|
||
".content3 > div:nth-child(3)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.6"
|
||
);
|
||
},
|
||
onLeaveBack: () => {
|
||
const tl = gsap.timeline({
|
||
defaults: {
|
||
duration: 0.3,
|
||
ease: "power2.in",
|
||
},
|
||
});
|
||
|
||
tl.to(
|
||
[
|
||
".content3 > div:nth-child(3)",
|
||
".content3 > div:nth-child(2)",
|
||
".content3 > div:nth-child(1)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: 30,
|
||
stagger: 0.1,
|
||
}
|
||
);
|
||
},
|
||
});
|
||
|
||
// 修改第四幕的动画配置
|
||
ScrollTrigger.create({
|
||
trigger: panels[3],
|
||
start: "top 80%",
|
||
end: "bottom center",
|
||
onEnter: () => {
|
||
// 进入第四幕时隐藏
|
||
scrollDownVisible.value = false;
|
||
// 初始状态设置
|
||
gsap.set(".content4", {
|
||
opacity: 1,
|
||
y: 0,
|
||
immediateRender: true,
|
||
});
|
||
|
||
// 预先设置所有元素的初始状态
|
||
gsap.set(
|
||
[
|
||
".content4 > div:nth-child(1)",
|
||
".content4 > div:nth-child(2)",
|
||
".content4 > div:nth-child(3)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: 30,
|
||
immediateRender: true,
|
||
}
|
||
);
|
||
|
||
// 单独设置卡片的初始状态
|
||
gsap.set(".content4 .container .card", {
|
||
opacity: 0,
|
||
y: 50,
|
||
immediateRender: true,
|
||
});
|
||
|
||
const tl = gsap.timeline({
|
||
defaults: {
|
||
duration: 0.6,
|
||
ease: "power2.out",
|
||
},
|
||
});
|
||
|
||
// 标题动画
|
||
tl.to(".content4 > div:nth-child(1)", {
|
||
opacity: 1,
|
||
y: 0,
|
||
})
|
||
.to(
|
||
".content4 > div:nth-child(2)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.4"
|
||
)
|
||
.to(
|
||
".content4 > div:nth-child(3)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.4"
|
||
)
|
||
// 卡片动画
|
||
.to(
|
||
".content4 .container > div:first-child .card:first-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.2"
|
||
)
|
||
.to(
|
||
".content4 .container > .right .card:first-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.6"
|
||
)
|
||
.to(
|
||
".content4 .container > div:first-child .card:last-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.6"
|
||
)
|
||
.to(
|
||
".content4 .container > .right .card:last-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.6"
|
||
);
|
||
},
|
||
onLeave: () => {
|
||
// 离开第四幕时显示
|
||
scrollDownVisible.value = true;
|
||
gsap
|
||
.timeline({
|
||
defaults: {
|
||
duration: 0.4,
|
||
ease: "power2.in",
|
||
},
|
||
})
|
||
.to(".content4 .container .card", {
|
||
opacity: 0,
|
||
y: -30,
|
||
stagger: {
|
||
each: 0.1,
|
||
from: "end",
|
||
},
|
||
})
|
||
.to(
|
||
[
|
||
".content4 > div:nth-child(3)",
|
||
".content4 > div:nth-child(2)",
|
||
".content4 > div:nth-child(1)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: -30,
|
||
stagger: 0.1,
|
||
},
|
||
"-=0.3"
|
||
);
|
||
},
|
||
onEnterBack: () => {
|
||
// 返回第四幕时隐藏
|
||
scrollDownVisible.value = false;
|
||
gsap.set(".content4", {
|
||
opacity: 1,
|
||
y: 0,
|
||
immediateRender: true,
|
||
});
|
||
|
||
gsap.set(
|
||
[
|
||
".content4 > div:nth-child(1)",
|
||
".content4 > div:nth-child(2)",
|
||
".content4 > div:nth-child(3)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: -30,
|
||
immediateRender: true,
|
||
}
|
||
);
|
||
|
||
gsap.set(".content4 .container .card", {
|
||
opacity: 0,
|
||
y: -50,
|
||
immediateRender: true,
|
||
});
|
||
|
||
const tl = gsap.timeline({
|
||
defaults: {
|
||
duration: 0.6,
|
||
ease: "power2.out",
|
||
},
|
||
});
|
||
|
||
tl.to(".content4 > div:nth-child(1)", {
|
||
opacity: 1,
|
||
y: 0,
|
||
})
|
||
.to(
|
||
".content4 > div:nth-child(2)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.4"
|
||
)
|
||
.to(
|
||
".content4 > div:nth-child(3)",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
},
|
||
"-=0.4"
|
||
)
|
||
.to(
|
||
".content4 .container > div:first-child .card:first-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.2"
|
||
)
|
||
.to(
|
||
".content4 .container > .right .card:first-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.6"
|
||
)
|
||
.to(
|
||
".content4 .container > div:first-child .card:last-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.6"
|
||
)
|
||
.to(
|
||
".content4 .container > .right .card:last-child",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: 0.8,
|
||
},
|
||
"-=0.6"
|
||
);
|
||
},
|
||
onLeaveBack: () => {
|
||
// 向上离开第四幕时显示
|
||
scrollDownVisible.value = true;
|
||
gsap
|
||
.timeline({
|
||
defaults: {
|
||
duration: 0.4,
|
||
ease: "power2.in",
|
||
},
|
||
})
|
||
.to(".content4 .container .card", {
|
||
opacity: 0,
|
||
y: 30,
|
||
stagger: {
|
||
each: 0.1,
|
||
from: "end",
|
||
},
|
||
})
|
||
.to(
|
||
[
|
||
".content4 > div:nth-child(3)",
|
||
".content4 > div:nth-child(2)",
|
||
".content4 > div:nth-child(1)",
|
||
],
|
||
{
|
||
opacity: 0,
|
||
y: 30,
|
||
stagger: 0.1,
|
||
},
|
||
"-=0.3"
|
||
);
|
||
},
|
||
});
|
||
}, main.value);
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
);
|
||
const carouselTrack = ref(null);
|
||
let carouselAnimation = null; // 存储 GSAP 动画实例
|
||
const getVisibleItems = () => {
|
||
const items = state.marqueeArr;
|
||
// 复制两组用于无缝滚动
|
||
return [...items, ...items];
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.page-container {
|
||
width: 100%;
|
||
overflow-x: hidden;
|
||
position: relative;
|
||
}
|
||
.header {
|
||
width: 100%;
|
||
height: 260px;
|
||
position: fixed;
|
||
z-index: 10;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
padding: 0 138px;
|
||
background-color: transparent;
|
||
}
|
||
.logo {
|
||
img {
|
||
width: 399px;
|
||
height: 128px;
|
||
}
|
||
}
|
||
|
||
.tabs {
|
||
display: flex;
|
||
gap: 128px;
|
||
margin-right: 32px;
|
||
}
|
||
|
||
.tab-item {
|
||
font-size: 61px;
|
||
color: #000000;
|
||
cursor: pointer;
|
||
transition: color 0.3s ease;
|
||
padding: 4px 8px;
|
||
|
||
&.active {
|
||
color: #8b59fa;
|
||
}
|
||
|
||
&:hover {
|
||
color: #8b59fa;
|
||
}
|
||
}
|
||
|
||
.title {
|
||
font-size: 113px;
|
||
font-weight: 600;
|
||
color: #10253e;
|
||
line-height: 143px;
|
||
}
|
||
.subTitle {
|
||
line-height: 102px;
|
||
}
|
||
.scroll-down {
|
||
position: fixed;
|
||
bottom: 50px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
color: #ffffff;
|
||
font-size: 82px;
|
||
font-weight: 600;
|
||
z-index: 999;
|
||
background: rgba(0, 0, 0, 0.1);
|
||
backdrop-filter: blur(20px);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
border-radius: 113px;
|
||
padding: 41px 143px;
|
||
animation: flot 2s ease-in-out infinite;
|
||
opacity: 1;
|
||
transition: opacity 0.3s ease;
|
||
min-width: 625px;
|
||
height: 195px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
&.hide {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
}
|
||
|
||
@keyframes float {
|
||
0%,
|
||
100% {
|
||
transform: translate(-50%, 0);
|
||
}
|
||
|
||
50% {
|
||
transform: translate(-50%, -10px);
|
||
}
|
||
}
|
||
|
||
:deep .n-carousel__dot {
|
||
background-color: #dddddd !important;
|
||
}
|
||
|
||
:deep .n-carousel__dot--active {
|
||
background-color: #8b59f7 !important;
|
||
}
|
||
|
||
.divider1 {
|
||
position: absolute;
|
||
z-index: 3;
|
||
left: 477px;
|
||
width: 1px;
|
||
height: 100vw;
|
||
}
|
||
|
||
.divider2 {
|
||
position: absolute;
|
||
z-index: 3;
|
||
left: 715px;
|
||
width: 1px;
|
||
height: 100vw;
|
||
background-image: linear-gradient(to bottom, #e6eaee 50%, transparent 50%);
|
||
background-size: 1px 15px; // 第一个值是宽度,第二个值是虚线的总长度(实线+空白)
|
||
background-repeat: repeat-y;
|
||
}
|
||
|
||
.divider3 {
|
||
position: absolute;
|
||
z-index: 3;
|
||
left: 950px;
|
||
width: 1px;
|
||
height: 100vw;
|
||
background-image: linear-gradient(to bottom, #e6eaee 50%, transparent 50%);
|
||
background-size: 1px 15px; // 第一个值是宽度,第二个值是虚线的总长度(实线+空白)
|
||
background-repeat: repeat-y;
|
||
}
|
||
|
||
.divider4 {
|
||
position: absolute;
|
||
z-index: 3;
|
||
left: 1186px;
|
||
width: 1px;
|
||
height: 100vw;
|
||
background-image: linear-gradient(to bottom, #e6eaee 50%, transparent 50%);
|
||
background-size: 1px 15px; // 第一个值是宽度,第二个值是虚线的总长度(实线+空白)
|
||
background-repeat: repeat-y;
|
||
}
|
||
|
||
.divider5 {
|
||
position: absolute;
|
||
z-index: 3;
|
||
left: 1420px;
|
||
width: 1px;
|
||
height: 100vw;
|
||
}
|
||
|
||
.carousel-img {
|
||
width: 100%;
|
||
height: 100vh;
|
||
object-fit: cover;
|
||
image-rendering: -webkit-optimize-contrast;
|
||
image-rendering: crisp-edges;
|
||
-webkit-backface-visibility: hidden;
|
||
backface-visibility: hidden;
|
||
transform: translateZ(0);
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
}
|
||
|
||
.panel {
|
||
height: 100vh;
|
||
position: sticky;
|
||
top: 0;
|
||
color: var(--dark);
|
||
font-size: 30px;
|
||
overflow: hidden;
|
||
|
||
// 为第四个panel添加特殊处理
|
||
&:last-child {
|
||
position: relative;
|
||
overflow-y: auto;
|
||
height: auto;
|
||
min-height: 100vh;
|
||
|
||
// 隐藏滚动条但保持功能
|
||
&::-webkit-scrollbar {
|
||
display: none; // Chrome, Safari, Opera
|
||
}
|
||
}
|
||
|
||
&.first-panel {
|
||
position: relative;
|
||
|
||
.carousel-img {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 1;
|
||
}
|
||
|
||
.content {
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
}
|
||
}
|
||
|
||
.parallax-bg {
|
||
position: absolute;
|
||
top: -10%;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 120%;
|
||
z-index: 1;
|
||
}
|
||
|
||
.content {
|
||
position: relative;
|
||
z-index: 5;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.content3 {
|
||
position: relative;
|
||
z-index: 5;
|
||
padding: 0 184px;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
> div {
|
||
opacity: 0;
|
||
transform: translateY(50px);
|
||
will-change: opacity, transform;
|
||
}
|
||
}
|
||
|
||
.content4 {
|
||
position: relative;
|
||
z-index: 5;
|
||
padding: 0 184px;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.no-hover {
|
||
pointer-events: none;
|
||
}
|
||
|
||
:deep(.no-hover) {
|
||
.n-carousel__dots,
|
||
.n-carousel__arrow {
|
||
pointer-events: auto;
|
||
}
|
||
}
|
||
|
||
.second-image {
|
||
opacity: 0;
|
||
padding: 0 64px;
|
||
transform: translateY(50px);
|
||
will-change: opacity, transform;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.divider3,
|
||
.divider4 {
|
||
:deep(.n-divider) {
|
||
border-left: none;
|
||
background-image: linear-gradient(to bottom, #e6eaee 50%, transparent 50%);
|
||
background-size: 1px 30px;
|
||
background-repeat: repeat-y;
|
||
}
|
||
}
|
||
|
||
.container {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
/* Two columns */
|
||
gap: 55px;
|
||
}
|
||
|
||
.card {
|
||
margin-top: 75px;
|
||
box-shadow: 0px 3px 14px 1px rgba(0, 0, 0, 0.16);
|
||
padding: 22px 18px 57px 20px;
|
||
border-radius: 30px;
|
||
background-color: #ffffff;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
}
|
||
|
||
.card img {
|
||
max-width: 100%;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.js-detail {
|
||
text-align: left;
|
||
margin-top: 37px;
|
||
font-size: 50px;
|
||
color: #10253e;
|
||
width: 100%;
|
||
padding: 0 20px 0 30px;
|
||
}
|
||
|
||
.carousel-container {
|
||
width: 96%;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
.arrow-btn {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.carousel-track {
|
||
display: flex;
|
||
will-change: transform;
|
||
cursor: grab;
|
||
user-select: none;
|
||
|
||
&:active {
|
||
cursor: grabbing;
|
||
}
|
||
}
|
||
|
||
.carousel-item {
|
||
width: 785px;
|
||
margin-right: 73px;
|
||
flex: 0 0 auto;
|
||
display: block; // 改为 block 布局
|
||
padding: 23px 20px 40px;
|
||
border-radius: 30px;
|
||
box-shadow: 0 8px 35px 3px rgba(0, 0, 0, 0.16);
|
||
}
|
||
|
||
.carousel-image {
|
||
width: 748px;
|
||
height: 563px;
|
||
object-fit: cover;
|
||
display: block;
|
||
}
|
||
|
||
.carousel-content {
|
||
padding: 0 20px 0 60px;
|
||
margin-top: 38px;
|
||
}
|
||
|
||
.carousel-title {
|
||
font-size: 50px;
|
||
font-weight: 500;
|
||
margin-top: 48px;
|
||
}
|
||
|
||
.carousel-subtitle {
|
||
margin-top: 23px;
|
||
color: #455363;
|
||
font-size: 40px;
|
||
}
|
||
</style>
|