仿照实现苹果音箱首页的滑动效果。因为没有接触过gsap就不知道有这东西,就打算自己用js写,写的很困难因为每个人的屏幕大小不一,本人的js水平也没很牛,导致写了很久虽然有效果但是不够流畅。后面上网搜了下意外发现gsap,看着案例慢慢试着写了写,终于实现了比之前的效果好。记录一下自己的实现:
1.配置文件nuxt.config.js引入gsap.js
{ src: "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"},
{ src: "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js" }
2.首页实现随着滑动,图片从下方移动到右中间,左侧同时出现步骤,右侧是图片,类似就是随着滑动两侧要同步图文注解。
<div class="yun-run">
<div class="main">
<div class="ywsy-scroll" ref="ywsyScroll">
<p class="title" ref="ywsyTitle">业务上云</p>
<div class="gdty">
<p>滚动体验</p>
<i class="iconfont icon-a-1_88"></i>
<div class="line"></div>
</div>
</div>
<div class="cloud-bz" ref="cloudBzScroll">
<div class="text-bz-con" ref="textLeft">
<div class="con">
<div class="left">
<div class="line"></div>
<div class="line-active"></div>
<ul class="title-list">
<li :class="{ 'active-li': imgActiveFlag == '1' }" @click="handleLineStep('1')">
<img v-if="imgActiveFlag == '1'" src="@/assets/index/cloud.webp" alt="" />
01 一键管理账号
</li>
<li :class="{ 'active-li': imgActiveFlag == '2' }" @click="handleLineStep('2')">
<img v-if="imgActiveFlag == '2'" src="@/assets/index/cloud.webp" alt="" />
02 自助授信,实时到账
</li>
<li :class="{ 'active-li': imgActiveFlag == '3' }" @click="handleLineStep('3')">
<img v-if="imgActiveFlag == '3'" src="@/assets/index/cloud.webp" alt="" />
03 余额预警,以防欠费
</li>
<li :class="{ 'active-li': imgActiveFlag == '4' }" @click="handleLineStep('4')">
<img v-if="imgActiveFlag == '4'" src="@/assets/index/cloud.webp" alt="" />
04 记录追溯,有迹可循
</li>
<li :class="{ 'active-li': imgActiveFlag == '5' }" @click="handleLineStep('5')">
<img v-if="imgActiveFlag == '5'" src="@/assets/index/cloud.webp" alt="" />
05 线上申请、下载发票
</li>
<li :class="{ 'active-li': imgActiveFlag == '6' }" @click="handleLineStep('6')">
<img v-if="imgActiveFlag == '6'" src="@/assets/index/cloud.webp" alt="" />
06 高效账单管理,便捷操作
</li>
</ul>
</div>
</div>
</div>
<div class="img-con" ref="images">
<img src="@/assets/index/bz-img1.webp" alt="" />
<img src="@/assets/index/bz-img2.webp" alt="" />
<img src="@/assets/index/bz-img3.webp" alt="" />
<img src="@/assets/index/bz-img4.webp" alt="" />
<img src="@/assets/index/bz-img5.webp" alt="" />
<img src="@/assets/index/bz-img6.webp" alt="" />
</div>
</div>
</div>
</div>
js部分
animateElement() {
const ywsyTitleText = this.$refs.ywsyTitle
const ywsyScrollPart = this.$refs.ywsyScroll
const cloudBzScrollPart = this.$refs.cloudBzScroll
const textLeft = this.$refs.textLeft
const images = Array.from(this.$refs.images.children)
// ScrollTrigger for text scaling
gsap.to(ywsyTitleText, { //根据滑动变化的DOM
fontSize: '670px',
scrollTrigger: {
trigger: ywsyScrollPart, //触发的DOM
start: 'top top',
end: '+=670',
scrub: true,
pin: true
},
})
// ScrollTrigger for complex image movement and text display
gsap.timeline({
scrollTrigger: {
trigger: cloudBzScrollPart,
start: 'top top',
end: '+=7000',
scrub: true,
pin: true,
// markers: true, // Remove this line in production; it's just for visualization
onUpdate: (self) => {
const scrollDirection = self.direction > 0 ? 'down' : 'up';
const currentScroll = self.scroll()
// Assuming each image section has a height of 100% of the viewport
const sectionHeight = window.innerHeight
let flag = Math.floor((currentScroll-3200) / sectionHeight) //3200自己慢慢调试效果
if(flag < 0){
flag = 1
}
if(flag > 6){
flag = 6
}
// Calculate the active image flag based on scroll position
this.imgActiveFlag = flag
},
}
})
.to(images[0], { opacity: 1 })
.fromTo(
images[0],
{ y: '0', x: '0' ,scale: '0.5'},
{ y: '-45%', x: '30%',scale: '1', duration: 100 }
)
.to(textLeft, { opacity: 1 })
.fromTo(
images[1],
{ y: '-45%', x: '30%' ,opacity: 0},
{ y: '-45%', x: '30%',opacity: 1 ,duration: 100 }
)
.fromTo(
images[2],
{ y: '-45%', x: '30%' ,opacity: 0},
{ y: '-45%', x: '30%',opacity: 1 ,duration: 100 }
)
.fromTo(
images[3],
{ y: '-45%', x: '30%' ,opacity: 0},
{ y: '-45%', x: '30%',opacity: 1 ,duration: 100 }
)
.fromTo(
images[4],
{ y: '-45%', x: '30%' ,opacity: 0},
{ y: '-45%', x: '30%',opacity: 1 ,duration: 100}
)
.fromTo(
images[5],
{ y: '-45%', x: '30%' ,opacity: 0},
{ y: '-45%', x: '30%',opacity: 1 ,duration: 100 }
)
}
scss部分
.yun-run {
.main {
position: relative;
height: 3260rem;
.tab-fixed {
display: flex;
align-items: center;
justify-content: center;
height: 1000rem;
width: 100%;
opacity: 1;
background: url(../../assets/index/bg1.webp) no-repeat 100% 100%/100%
100%;
.title {
text-align: center;
font-size: 200rem;
font-weight: 500;
color: #ffffff;
white-space: nowrap;
}
}
.ywsy-scroll {
display: flex;
align-items: center;
justify-content: center;
height: 1000rem;
width: 100%;
background: url(../../assets/index/bg1.webp) no-repeat 100% 100%/100%
100%;
.title {
text-align: center;
font-size: 200rem;
font-weight: 500;
color: #ffffff;
white-space: nowrap;
}
.gdty {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
& > p {
font-size: 20rem;
font-weight: 400;
line-height: 42rem;
color: #ffffff;
}
& > i {
margin: 20rem 0;
font-size: 56rem;
color: #fff;
}
.line {
width: 1rem;
height: 43rem;
border-left: 3px dashed #ffffff;
}
}
}
.cloud-bz {
display: flex;
justify-content: space-around;
align-items: center;
background-color: #fafcff;
width: 100%;
height: 806rem;
opacity: 1;
.text-bz-con {
position: absolute;
left: 200rem;
top: 158rem;
opacity: 0;
.con {
.left {
display: flex;
.line {
position: absolute;
top: 8rem;
width: 2rem;
height: 600rem;
border: 2px dashed #dddddd;
left: 5rem;
z-index: -1;
}
.line-active {
position: absolute;
top: 8rem;
width: 2rem;
height: 0;
border: 2px dashed #4ca574;
left: 5rem;
z-index: 0;
}
.cloud-move {
position: absolute;
left: -16rem;
top: 8rem;
& > img {
width: 45.29rem;
}
}
.title-list {
height: 600rem;
display: flex;
flex-direction: column;
justify-content: space-between;
& > li {
font-size: 24rem;
line-height: 41rem;
color: #999999;
cursor: pointer;
&::before {
margin-right: 35rem;
display: inline-block;
content: '';
width: 15rem;
height: 15rem;
background: #4ca574;
border-radius: 50%;
}
}
.active-li {
position: relative;
font-size: 32rem;
line-height: 54rem;
color: #000000;
&>img {
position: absolute;
top: 10rem;
left: -16rem;
}
}
}
}
}
}
.img-con {
display: flex;
justify-content: space-around;
position: relative;
& > img {
opacity: 0;
transition: opacity 0.5s;
position: absolute;
width: 1144rem;
}
}
}
}
}