Vue 实现全屏滚动效果

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;
      }
    }
  }
}

效果图(静态)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值