Vue实现全屏滚动效果
结构部分
<template>
<div class="full-page" ref="page">
<div
class="list"
ref="container"
@mousewheel="mouseWheel"
@DOMMouseScroll="mouseWheel"
>
<div class="item red">
<h1>Page 1.</h1>
<div class="content">
<div class="info">
<div
class="avatar"
:class="itemIndex === 1 ? 'avatar-act' : 'item-blur'"
>
K
</div>
<div
class="name"
:class="itemIndex === 1 ? 'name-act' : 'item-blur'"
>
Kay
</div>
</div>
<div class="desc" :class="itemIndex === 1 ? 'desc-act' : 'item-blur'">
<i>This is description.</i>
</div>
</div>
</div>
<div class="item blue">
<h1>Page 2.</h1>
<div class="content">
<div
class="logo"
:class="itemIndex === 2 ? 'logo-act' : 'item-blur'"
></div>
<div
class="slogan"
:class="itemIndex === 2 ? 'slogan-act' : 'item-blur'"
>
<i>This is slogan.</i>
</div>
</div>
</div>
<div class="item green">
<h1>Page 3.</h1>
<div class="content">
<div
class="title"
:class="itemIndex === 3 ? 'title-act' : 'item-blur'"
>
This is the title for post.
</div>
<div class="post" :class="itemIndex === 3 ? 'post-act' : 'item-blur'">
<i>
In the flood of darkness, hope is the light. It brings comfort,
faith, and confidence. It gives us guidance when we are lost, and
gives support when we are afraid. And the moment we give up hope,
we give up our lives. The world we live in is disintegrating into
a place of malice and hatred, where we need hope and find it
harder. In this world of fear, hope to find better, but easier
said than done, the more meaningful life of faith will make life
meaningful.
</i>
</div>
</div>
</div>
<div class="item gray">
<h1>Page 4.</h1>
<div
class="content"
:class="itemIndex === 4 ? 'content-act' : 'item-blur'"
>
The end.
</div>
</div>
</div>
<div class="points">
<div
v-for="(e, i) in 4"
class="item"
:key="e"
:class="itemIndex === i + 1 ? 'item-act' : ''"
></div>
</div>
</div>
</template>
JS部分
export default {
name: "FullPageScroll",
data() {
return {
isScroll: false, // 是否能滚动
itemIndex: 0, // 当前下标
len: 4, // 总个数
};
},
methods: {
handleMove() {
this.isScroll = true;
const scrollHeight = this.$refs.page.clientHeight;
this.$refs.container.style.transform = `translateY(-${
(this.itemIndex - 1) * scrollHeight
}px)`;
setTimeout(() => (this.isScroll = false), 1300); // 防止连续滚动,加延时
},
mouseWheel(event) {
if (this.isScroll) { // 防止连续滚动
return false;
}
if (event.deltaY > 0) {
if (this.itemIndex === this.len) return; // 最后一个禁止向下滚动
this.itemIndex += 1;
} else {
if (this.itemIndex === 1) return; // 第一个禁止向上滚动
this.itemIndex -= 1;
}
this.handleMove();
},
},
mounted() {
setTimeout(() => (this.itemIndex += 1), 10); // 初始加一,为了加载第一页动画
},
};
CSS
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(100px);
}
to {
opacity: 1;
transform: translateY(0px);
}
}
@keyframes slideLeft {
from {
opacity: 0;
transform: translateX(-100%);
}
to {
opacity: 1;
transform: translateX(0px);
}
}
@keyframes slideRight {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0px);
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(-100%);
}
to {
opacity: 1;
transform: translateX(0px);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(100%);
}
to {
opacity: 1;
transform: translateX(0px);
}
}
.full-page {
width: 100vw;
height: 100vh;
position: relative;
overflow: hidden;
.list {
width: 100vw;
transition: 1s;
.item {
height: 100vh;
transition: 1s all;
.item-blur {
opacity: 1 !important;
}
h1 {
padding: 20px;
font-size: 24px;
margin: 0px;
}
&.red {
h1 {
color: red;
}
background-color: rgba($color: red, $alpha: 0.1);
.content {
width: 600px;
margin: auto;
padding-top: 200px;
.info {
display: flex;
align-items: center;
.avatar {
width: 80px;
height: 80px;
margin-right: 20px;
background-color: rgba($color: #fff, $alpha: 0.6);
border-radius: 80px;
overflow: hidden;
text-align: center;
line-height: 80px;
font-size: 24px;
color: #999;
opacity: 0;
&.avatar-act {
animation: fadeIn 1s 0s forwards;
}
}
.name {
font-size: 24px;
opacity: 0;
&.name-act {
animation: fadeIn 1s 0.5s forwards;
}
}
}
.desc {
margin-left: 100px;
font-size: 36px;
font-weight: bold;
opacity: 0;
&.desc-act {
animation: fadeIn 1s 1s forwards;
}
}
}
}
&.blue {
h1 {
color: blue;
}
background-color: rgba($color: blue, $alpha: 0.1);
.content {
width: 400px;
margin: 300px auto;
position: relative;
.logo {
width: 100%;
height: 80px;
border-radius: 10px;
position: absolute;
border: 4px solid rgba($color: blue, $alpha: 0.3);
opacity: 0;
&.logo-act {
animation: slideLeft 0.8s 0.2s forwards;
}
}
.slogan {
height: 80px;
line-height: 80px;
text-align: center;
color: rgba($color: blue, $alpha: 0.5);
font-size: 38px;
font-weight: bold;
opacity: 0;
&.slogan-act {
animation: slideRight 0.8s 0.2s forwards;
}
}
}
}
&.green {
h1 {
color: green;
}
background-color: rgba($color: green, $alpha: 0.1);
.content {
width: 500px;
margin: 200px auto;
color: green;
.title {
margin-bottom: 10px;
text-align: center;
font-size: 24px;
opacity: 0;
&.title-act {
animation: slideUp 0.8s 0.5s forwards;
}
}
.post {
font-size: 16px;
text-indent: 2rem;
opacity: 0;
&.post-act {
animation: slideDown 0.6s 0.7s forwards;
}
}
}
}
&.gray {
h1 {
color: gray;
}
background-color: rgba($color: gray, $alpha: 0.4);
.content {
margin-top: 200px;
font-size: 42px;
text-align: center;
font-weight: bold;
color: gray;
opacity: 0;
&.content-act {
animation: slideUp 1s 0.5s forwards;
}
}
}
}
}
.points {
position: fixed;
top: 50%;
transform: translateY(-50%);
right: 10px;
.item {
width: 4px;
height: 20px;
margin-bottom: 25px;
background-color: rgba($color: gray, $alpha: 0.5);
transition: 1s;
&.item-act {
height: 50px;
background-color: #fff;
}
}
}
}
效果图(静态)