原理

有点类似于轮播,整体的元素一直排列下去,假设有 5 个需要展示的全屏页面,那么高度是 500%,只是展示 100%,容器及容器内的页面取当前可视区高度,同时容器的父级元素 overflow 属性值设为 hidden,通过更改容器可视区的位置来实现全屏滚动效果。主要是响应鼠标事件,页面通过 CSS 的动画效果,进行移动。

大致结构

  • html
<div id="container">
  <div class="page">page1</div>
  <div class="page">page2</div>
  <div class="page">page3</div>
  <!-- /...... -->
</div>
  • css
.container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
.page {
  width: 100%;
  height: 100vh;
}

主要是外层有个宽高为屏幕宽高的容器,里面的页面宽度为屏幕宽度,高度为屏幕高度,超出的页面被容器隐藏

切换动效

主要将容器的 transform: translateY(xxpx) 设置为负数,步长为屏幕高度,以实现全屏切换,如:transform: translateY(-100vh),向上移动一个屏幕的高度

  • 伪代码
$(".toggleBtn").click(function(item) {
  const pageNum = $(item).attr("pageNum"); // 要切换到第几个页面, 从1开始
  $("#container").css({ transform: `translateY(-${(pageNum - 1) * 100}vh)` }); // 向上移动x个屏幕的高度
});
  • 加上过渡动效
.container {
  transition: all 0.6s ease-in-out;
}

这样当 translateY 发生改变时就会有过渡动效

鼠标滚动轴

以上只是实现了菜单点击的切换思路,接下来看看鼠标滚轴切换

  • 思路
    根据鼠标滚轴的滚动方向(上下)决定切换到上一页面还是下一页面
// 鼠标滚轴监听
window.addEventListener("mousewheel", e => {
  console.log(e.wheelDelta);
  if (e.wheelDelta < 0) {
    // 向下
    // 根据当前是第几个页面,计算 当前页面的translateY + 下一屏高度100vh 再取负数
  } else {
    // 向上
    // 根据当前是第几个页面,计算 当前页面的translateY - 上一屏高度100vh 再取负数
  }
});

vue代码示例

<template>
  <div class="body">
    <div class="nav">
      <a
        v-for="i in pageCount"
        :href="`#panel${i}`"
        :class="{ active: currentPage === i }"
        :key="i"
        @click="toggle(i)"
        >页面{{ i }}</a
      >
    </div>
    <div class="scroll" ref="scroll" :style="scrollStyle">
      <div v-for="i in pageCount" :key="i" class="page">第{{ i }}个页面</div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      pageCount: 6,
      currentPage: 1
    };
  },
  computed: {
    scrollStyle() {
      return { transform: `translateY(-${(this.currentPage - 1) * 100}vh)` };
    }
  },
  methods: {
    toggle(i) {
      this.currentPage = i;
    },
    moushWheel(e) {
      console.log(e.wheelDelta);
      if (e.wheelDelta < 0) {
        // 向下
        this.currentPage =
          this.currentPage + 1 < this.pageCount
            ? this.currentPage + 1
            : this.pageCount;
      } else {
        // 向上
        this.currentPage = this.currentPage - 1 > 0 ? this.currentPage - 1 : 1;
      }
    }
  },
  mounted() {
    // 鼠标滚轴监听
    window.addEventListener("mousewheel", this.moushWheel);
  },
  beforeDestroy() {
    // 移除鼠标滚动轴监听
    window.removeEventListener("mousewheel", this.moushWheel);
  }
};
</script>

<style lang="scss" scoped>
.body {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: #3f3f3f;
}
.nav {
  width: 100%;
  height: 35px;
  display: flex;
  align-items: center;
  position: fixed;
  left: 0;
  top: 0;
  z-index: 999;

  a {
    flex-grow: 1;
    text-align: center;
  }

  .active {
    background: pink;
    color: green;
    font-weight: bold;
  }
}
.scroll {
  transition: all 0.6s ease-in-out;

  .page {
    height: 100vh;

    text-align: center;
    padding-top: 40vh;
    color: #fff;
  }

  .page:nth-child(even) {
    background: rgb(15, 19, 10);
  }
}
</style>

效果

img


zpfei
186 声望7 粉丝

往事如风~


« 上一篇
div居中