Skip to content

前端强制阅读到底功能实现 Vue3

业务背景

在一些需要用户仔细阅读内容的场景中,例如用户协议、重要通知或分步教程,我们可能希望用户在点击下一步之前必须阅读完整个页面内容。这种“强制阅读到底”的功能可以通过前端技术实现,本文将通过 Vue3 来展示如何实现这一功能。

功能介绍

这个功能的核心逻辑是:用户必须滚动到内容区域的底部,才能解锁“下一步”按钮。一旦解锁,按钮将保持可点击状态,即使用户再次向上滚动,也不会被禁用。这种设计可以确保用户在继续操作之前已经阅读了所有内容。

实现步骤

通过 Vue 的 ref 创建一个引用,指向页面中的内容区域。这样我们可以在 JavaScript 中操作这个 DOM 元素。

js
const contentRef = ref(null);

<div ref="contentRef" class="content" @scroll="handleScroll">

当用户滚动内容区域时,触发 handleScroll 方法。这个方法会调用 checkScroll 函数来判断是否滚动到底部。

js
const handleScroll = () => {
  checkScroll();
};

在 checkScroll 函数中,通过 DOM 元素的 scrollHeightscrollTopclientHeight 属性来判断是否滚动到底部。具体逻辑如下:

scrollHeight:内容区域的总高度,包括超出视口的部分。

scrollTop:当前滚动条的垂直位置。

clientHeight:内容区域的可见高度(视口高度)。

scrollHeight - scrollTop <= clientHeight 时,表示用户已经滚动到底部。

js

const checkScroll = () => {
  const contentElement = contentRef.value;
  if (contentElement) {
    const isAtBottom = contentElement.scrollHeight - contentElement.scrollTop <= contentElement.clientHeight;
    if (isAtBottom && !hasReachedBottom.value) {
      hasReachedBottom.value = true;
      canClickNext.value = true;
    }
  }
};

根据用户是否滚动到底部,动态控制“下一步”按钮的可点击状态。

定义两个变量来控制按钮的状态:

  • canClickNext:布尔值,表示按钮是否可点击。

  • hasReachedBottom:布尔值,表示是否已经滚动到底部。

js
const canClickNext = ref(false);
const hasReachedBottom = ref(false);

示例代码

<script setup>
import { ref } from 'vue';

// 定义一个变量来控制按钮是否可点击
const canClickNext = ref(false);

// 定义一个变量来记录是否已经滚动到底部
const hasReachedBottom = ref(false);

// 使用 ref 来引用内容区域的 DOM 元素
const contentRef = ref(null);

// 定义一个方法来检测是否滚动到底部
const checkScroll = () => {
  const contentElement = contentRef.value;
  if (contentElement) {
    const isAtBottom = contentElement.scrollHeight - contentElement.scrollTop <= contentElement.clientHeight;
    if (isAtBottom && !hasReachedBottom.value) {
      // 如果滚动到底部且之前没有滚动到底部过,解锁按钮
      hasReachedBottom.value = true;
      canClickNext.value = true;
    }
  }
};

// 挂载滚动事件监听
const handleScroll = () => {
  checkScroll();
};
</script>

<template>
  <div ref="contentRef" class="content" @scroll="handleScroll">
    <p>
      这是一个示例文本,用于演示强制阅读到底才能点击下一步按钮的功能。
      你可以在这里添加更多内容,以测试滚动效果。
    </p>
    <p>
      请滚动到底部,以解锁“下一步”按钮。
    </p>
    <p>
      这里有更多的内容,确保你阅读完整个页面。
    </p>
    <p>
      继续滚动,直到你到达页面底部。
    </p>
    <p>
      最后一段内容,滚动到底部后,按钮将变为可点击状态。
    </p>
    <p>
      如果你向上滚动,按钮不会再次被禁用。
    </p>
    <p>
      这是一个示例文本,用于演示强制阅读到底才能点击下一步按钮的功能。
      你可以在这里添加更多内容,以测试滚动效果。
    </p>
    <p>
      请滚动到底部,以解锁“下一步”按钮。
    </p>
    <p>
      这里有更多的内容,确保你阅读完整个页面。
    </p>
    <p>
      继续滚动,直到你到达页面底部。
    </p>
    <p>
      最后一段内容,滚动到底部后,按钮将变为可点击状态。
    </p>
    <p>
      如果你向上滚动,按钮不会再次被禁用。
    </p>
    <p>
      这是一个示例文本,用于演示强制阅读到底才能点击下一步按钮的功能。
      你可以在这里添加更多内容,以测试滚动效果。
    </p>
    <p>
      请滚动到底部,以解锁“下一步”按钮。
    </p>
    <p>
      这里有更多的内容,确保你阅读完整个页面。
    </p>
    <p>
      继续滚动,直到你到达页面底部。
    </p>
    <p>
      最后一段内容,滚动到底部后,按钮将变为可点击状态。
    </p>
    <p>
      如果你向上滚动,按钮不会再次被禁用。
    </p>
  </div>
  <button :disabled="!canClickNext" @click="nextStep" class="next-button">
    下一步
  </button>
</template>

<style scoped>
.content {
  height: 300px;
  overflow-y: auto;
  border: 1px solid #ccc;
  margin-bottom: 10px;
  padding: 10px;
  border-radius: 8px; /* 添加圆角边框 */
  background-color: #f9f9f9; /* 添加背景色 */
  font-family: Arial, sans-serif; /* 设置字体 */
  color: #333; /* 设置字体颜色 */
}

.next-button {
  display: block;
  margin: 20px auto 0; /* 增加上下外边距 */
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
  border: none; /* 去掉边框 */
  border-radius: 5px; /* 添加圆角边框 */
  background-color: #007bff; /* 设置按钮背景色 */
  color: #fff; /* 设置按钮字体颜色 */
  transition: background-color 0.3s ease; /* 添加背景色过渡效果 */
}

.next-button:hover {
  background-color: #0056b3; /* 鼠标悬停时的背景色 */
}

.next-button:disabled {
  background-color: #ccc; /* 禁用状态的背景色 */
  cursor: not-allowed;
  color: #888; /* 禁用状态的字体颜色 */
}
</style>