鼠标纵向滚屏翻页(vue3版本和html+css+js版本)

111 阅读2分钟

门户网站中往往有比较多的特效,其中鼠标纵向滚屏翻页就是一种比较常见的效果,接下来我们用两种版本来实现这个效果

html+css+js版本效果演示

html+css+js版本代码

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>纵向滚屏翻页</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
        }
        .section {
            width: 100%;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 24px;
            color: white;
            transition: transform 0.5s ease;
        }
        .section:nth-child(1) { background-color: #FFA726; }
        .section:nth-child(2) { background-color: #F57C00; }
        .section:nth-child(3) { background-color: #EF6C00; }
        
        .pagination {
            position: fixed;
            right: 20px;
            top: 50%;
            transform: translateY(-50%);
        }
        .pagination li {
            list-style: none;
            margin: 10px 0;
            cursor: pointer;
            width: 10px;
            height: 10px;
            background-color: #8D6E63;
            border-radius: 50%;
        }
        .pagination li.active {
            background-color: #FFF3E0;
        }
    </style>
</head>
<body>
    <div class="sections">
        <div class="section">页面 1</div>
        <div class="section">页面 2</div>
        <div class="section">页面 3</div>
    </div>
    <ul class="pagination">
        <li></li>
        <li></li>
        <li></li>
    </ul>

    <script>
        const sections = document.querySelectorAll('.section');
        const paginationDots = document.querySelectorAll('.pagination li');
        
        let currentSectionIndex = 0;

        function scrollToSection(index) {
            sections.forEach((section, i) => {
                section.style.transform = `translateY(-${index * 100}vh)`;
            });
            paginationDots.forEach(dot => dot.classList.remove('active'));
            paginationDots[index].classList.add('active');
            currentSectionIndex = index;
        }

        paginationDots.forEach((dot, index) => {
            dot.addEventListener('click', () => scrollToSection(index));
        });

        document.addEventListener('keydown', (event) => {
            if (event.key === 'ArrowDown' && currentSectionIndex < sections.length - 1) {
                scrollToSection(currentSectionIndex + 1);
            } else if (event.key === 'ArrowUp' && currentSectionIndex > 0) {
                scrollToSection(currentSectionIndex - 1);
            }
        });

        document.addEventListener('wheel', (event) => {
            if (event.deltaY > 0 && currentSectionIndex < sections.length - 1) {
                scrollToSection(currentSectionIndex + 1);
            } else if (event.deltaY < 0 && currentSectionIndex > 0) {
                scrollToSection(currentSectionIndex - 1);
            }
        });

        scrollToSection(0);
    </script>
</body>
</html>

vue3版本版本效果演示

vue3版本代码实现

<template>
  <div
    class="container"
    @wheel.prevent="handleWheel"
    @keydown="handleKeydown"
    tabindex="0"
  >
    <div
      class="section"
      v-for="(section, index) in sections"
      :key="index"
      :style="{ backgroundColor: section.color }"
    >
      <h1>{{ section.title }}</h1>
    </div>
    <div class="pagination">
      <div
        class="dot"
        v-for="(section, index) in sections"
        :key="index"
        :class="{ active: currentIndex === index }"
        @click="scrollToSection(index)"
      ></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const sections = ref([
  { title: '页面 1', color: '#FFA726' },
  { title: '页面 2', color: '#F57C00' },
  { title: '页面 3', color: '#EF6C00' },
])

const currentIndex = ref(0)

const scrollToSection = (index: number) => {
  currentIndex.value = index
  const container = document.querySelector('.container') as HTMLElement
  container.style.transform = `translateY(-${index * 100}vh)`
}

const handleWheel = (event: WheelEvent) => {
  if (event.deltaY > 0 && currentIndex.value < sections.value.length - 1) {
    scrollToSection(currentIndex.value + 1)
  } else if (event.deltaY < 0 && currentIndex.value > 0) {
    scrollToSection(currentIndex.value - 1)
  }
}

const handleKeydown = (event: KeyboardEvent) => {
  if (
    event.key === 'ArrowDown' &&
    currentIndex.value < sections.value.length - 1
  ) {
    scrollToSection(currentIndex.value + 1)
  } else if (event.key === 'ArrowUp' && currentIndex.value > 0) {
    scrollToSection(currentIndex.value - 1)
  }
}

onMounted(() => {
  const container = document.querySelector('.container') as HTMLElement
  container.focus() // 自动聚焦容器以接收键盘事件
})
</script>

<style scoped>
.container {
  position: relative;
  height: 100vh;
  overflow: hidden;
  outline: none; /* 移除键盘聚焦时的轮廓 */
}

.section {
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  font-size: 2rem;
  transition: transform 0.5s ease;
}

.pagination {
  position: fixed;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
}

.dot {
  width: 10px;
  height: 10px;
  background-color: #8d6e63;
  border-radius: 50%;
  margin: 10px 0;
  cursor: pointer;
}

.dot.active {
  background-color: #fff3e0;
}
</style>

后续优化 (留给所需要的人去干吧)

对滚轮和键盘事件添加防抖优化,以提高性能并防止事件过于频繁地触发

  1. 防抖函数: 添加了一个 debounce 函数,接受一个函数和延迟时间作为参数,确保在指定时间内不会重复触发函数。
  2. 应用于事件处理: 在 handleWheel 和 handleKeydown 函数上应用该防抖处理,以避免因滚动或按键事件过于频繁而导致的性能下降。