335 lines
7.6 KiB
Vue
335 lines
7.6 KiB
Vue
|
<script setup>
|
||
|
import { NCarousel } from 'naive-ui'
|
||
|
import { onUnmounted, ref, watch } from 'vue';
|
||
|
import gsap from 'gsap';
|
||
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||
|
import { useHome } from '@/store/home/index.js';
|
||
|
import { useTransitionComposable } from '@/composables/transition-composable';
|
||
|
|
||
|
const { transitionState } = useTransitionComposable();
|
||
|
const main = ref();
|
||
|
const secondImage = ref(null);
|
||
|
let scrollTween;
|
||
|
let ctx;
|
||
|
const { currentTab } = useHome();
|
||
|
|
||
|
const handleTabClick = (tab) => {
|
||
|
currentTab.value = tab;
|
||
|
}
|
||
|
|
||
|
const goToSection = (i) => {
|
||
|
ctx.data.forEach((e) => {
|
||
|
if (e.vars && e.vars.id === 'scrollTween') {
|
||
|
e.kill();
|
||
|
}
|
||
|
});
|
||
|
ctx.add(() => {
|
||
|
scrollTween = gsap.to(window, {
|
||
|
scrollTo: { y: i * window.innerHeight, autoKill: false },
|
||
|
duration: 1,
|
||
|
id: 'scrollTween',
|
||
|
onComplete: () => (scrollTween = null),
|
||
|
overwrite: true,
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
|
||
|
watch(
|
||
|
[() => transitionState.transitionComplete, main],
|
||
|
(newValue) => {
|
||
|
if (newValue && main.value) {
|
||
|
ctx = gsap.context((self) => {
|
||
|
const panels = self.selector('.panel');
|
||
|
|
||
|
// 移除之前的渐入动画代码
|
||
|
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: panel,
|
||
|
start: 'top bottom',
|
||
|
end: '+=200%',
|
||
|
onToggle: (self) => self.isActive && !scrollTween && goToSection(i),
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// 修改第二个面板的动画配置
|
||
|
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.create({
|
||
|
start: 0,
|
||
|
end: 'max',
|
||
|
snap: 1 / (panels.length - 1),
|
||
|
});
|
||
|
|
||
|
|
||
|
}, main.value);
|
||
|
}
|
||
|
},
|
||
|
{ immediate: true }
|
||
|
);
|
||
|
|
||
|
onUnmounted(() => {
|
||
|
ctx.revert();
|
||
|
ScrollTrigger.killAll();
|
||
|
});
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<header className="header">
|
||
|
<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')"
|
||
|
>
|
||
|
首页
|
||
|
</div>
|
||
|
<div
|
||
|
class="tab-item"
|
||
|
:class="{ active: currentTab === 'company' }"
|
||
|
@click="handleTabClick('company')"
|
||
|
>
|
||
|
公司概况
|
||
|
</div>
|
||
|
<div
|
||
|
class="tab-item"
|
||
|
:class="{ active: currentTab === 'business' }"
|
||
|
@click="handleTabClick('business')"
|
||
|
>
|
||
|
业务介绍
|
||
|
</div>
|
||
|
</div>
|
||
|
</header>
|
||
|
<main ref="main">
|
||
|
<section className="panel first-panel">
|
||
|
<n-carousel autoplay :interval="5000" class="no-hover">
|
||
|
<img class="carousel-img" src="@/assets/image/banner/cn/b1.jpg">
|
||
|
<img class="carousel-img" src="@/assets/image/banner/cn/b2.jpg">
|
||
|
<img class="carousel-img" src="@/assets/image/banner/cn/b3.jpg">
|
||
|
</n-carousel>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section className="panel" style="background-color: rgba(248, 249, 255, 1);">
|
||
|
<div class="parallax-bg" style="margin-top: 70px;">
|
||
|
<img
|
||
|
ref="secondImage"
|
||
|
class="second-image"
|
||
|
src="@/assets/image/head.png"
|
||
|
>
|
||
|
<div class="pop1">
|
||
|
<img class="w-[88px] h-[32px]" src="@/assets/image/panel2/pop1.png" alt="pop1">
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="content">
|
||
|
<div class="text-[#10253E] text-[54px] leading-[80px]">FiEE携手文艺创作者</div>
|
||
|
<div class="text-[#10253E] text-[54px] leading-[80px]">启航全球影响力新征程</div>
|
||
|
</div>
|
||
|
</section>
|
||
|
|
||
|
<section className="panel">
|
||
|
<div class="parallax-bg">THREE</div>
|
||
|
<div class="content">
|
||
|
<!-- 添加你的内容 -->
|
||
|
</div>
|
||
|
</section>
|
||
|
|
||
|
<section className="panel">
|
||
|
<div class="parallax-bg">FOUR</div>
|
||
|
<div class="content">
|
||
|
<!-- 添加你的内容 -->
|
||
|
</div>
|
||
|
</section>
|
||
|
</main>
|
||
|
</template>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
.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;
|
||
|
}
|
||
|
|
||
|
.header {
|
||
|
width: 100%;
|
||
|
height: 55px;
|
||
|
display: flex;
|
||
|
justify-content: space-between;
|
||
|
align-items: flex-end;
|
||
|
position: fixed;
|
||
|
z-index: 10;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
right: 0;
|
||
|
padding: 0 10rem;
|
||
|
background-color: transparent;
|
||
|
}
|
||
|
|
||
|
.logo {
|
||
|
img {
|
||
|
width: 108px;
|
||
|
height: 33px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.tabs {
|
||
|
display: flex;
|
||
|
gap: 32px;
|
||
|
margin-right: 32px;
|
||
|
}
|
||
|
|
||
|
.tab-item {
|
||
|
font-size: 16px;
|
||
|
color: #000000;
|
||
|
cursor: pointer;
|
||
|
transition: color 0.3s ease;
|
||
|
padding: 4px 8px;
|
||
|
|
||
|
&.active {
|
||
|
color: #8B59FA;
|
||
|
}
|
||
|
|
||
|
&:hover {
|
||
|
color: #8B59FA;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.panel {
|
||
|
height: 100vh;
|
||
|
position: sticky;
|
||
|
top: 0;
|
||
|
color: var(--dark);
|
||
|
font-size: 30px;
|
||
|
overflow: hidden;
|
||
|
|
||
|
&.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: 2;
|
||
|
height: 100%;
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
justify-content: center;
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
.no-hover {
|
||
|
pointer-events: none;
|
||
|
}
|
||
|
|
||
|
:deep(.no-hover) {
|
||
|
|
||
|
.n-carousel__dots,
|
||
|
.n-carousel__arrow {
|
||
|
pointer-events: auto;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.second-image {
|
||
|
opacity: 0;
|
||
|
transform: translateY(50px);
|
||
|
will-change: opacity, transform;
|
||
|
pointer-events: none;
|
||
|
}
|
||
|
</style>
|