0

0

利用MUI useScrollTrigger实现粘性组件在父容器底部自动隐藏

碧海醫心

碧海醫心

发布时间:2025-11-23 12:16:15

|

481人浏览过

|

来源于php中文网

原创

利用MUI useScrollTrigger实现粘性组件在父容器底部自动隐藏

本文详细介绍了如何在material-ui (mui) 应用中,利用`usescrolltrigger`钩子结合react的`useref`和`useeffect`,实现一个粘性组件在其父容器滚动到底部时自动隐藏的交互效果。通过动态设置`usescrolltrigger`的目标元素和滚动阈值,开发者可以精确控制粘性元素的显示与隐藏逻辑,从而优化用户体验,避免粘性元素遮挡底部内容。

MUI中粘性定位(position="sticky")基础

Material-UI (MUI) 提供了强大的布局组件,其中Box组件通过position="sticky"属性可以轻松实现粘性定位效果。当一个元素被设置为position="sticky"时,它在正常流中表现为相对定位,但在滚动到特定阈值时会“粘”在屏幕的某个位置(如顶部、底部),直到其父容器的边界将其“推”走。

通常,我们会将一个Box元素设置为position="sticky"和bottom={0},使其在滚动时粘在父容器的底部。然而,在某些场景下,我们希望当用户滚动到父容器的底部时,这个粘性元素能够自动隐藏,以避免遮挡父容器的最终内容或提供更流畅的交互体验。

挑战:在父容器滚动到底部时隐藏粘性元素

直接使用position="sticky"无法原生实现“在父容器底部时隐藏”的逻辑。MUI的useScrollTrigger钩子是一个强大的工具,它通常用于监听窗口的滚动事件,以触发如App Bar的提升效果或“返回顶部”按钮的显示。然而,其默认行为是监听全局window对象的滚动。我们的挑战在于如何让useScrollTrigger监听特定的父容器,并根据该父容器的滚动位置来控制粘性元素的可见性。

解决方案:useScrollTrigger与React.useRef的结合

要解决这个问题,我们需要将useScrollTrigger的目标(target)属性指向我们的可滚动父容器。这可以通过React的useRef钩子来获取DOM元素的引用,并结合React.useState和React.useEffect来动态设置useScrollTrigger的target。

1. 准备父容器与粘性元素

首先,构建一个包含可滚动内容的父容器Box和一个粘性子Box。父容器需要设置overflow: 'auto'或overflow: 'scroll'使其可滚动。

import React from 'react';
import { Box, useScrollTrigger } from '@mui/material';

export default function StickyDivControl() {
  const parentRef = React.useRef(null); // 创建一个ref来引用父容器

  // ... 后续逻辑

  return (
    
      
    {/* 生成大量内容使父容器可滚动 */} {Array.from({ length: 100 }, (_, index) => (
  • {`Text ${index + 1}`}
  • ))}
{/* 粘性元素,初始定位在底部 */} 这是一个粘性元素
); }

2. 获取父容器引用并动态设置useScrollTrigger的目标

useRef在组件初次渲染时,其.current属性可能为null。而useScrollTrigger的target属性期望一个DOM元素。因此,我们需要在组件挂载后,确保ref.current已经指向了DOM元素时,再将其传递给useScrollTrigger。这可以通过useState和useEffect实现。

import React from 'react';
import { Box, useScrollTrigger } from '@mui/material';

export default function StickyDivControl() {
  const parentRef = React.useRef(null);
  const [scrollTargetNode, setScrollTargetNode] = React.useState(undefined);

  // 在组件挂载后,将ref.current赋值给state,作为useScrollTrigger的target
  React.useEffect(() => {
    setScrollTargetNode(parentRef.current);
  }, []); // 空依赖数组确保只在组件挂载时运行一次

  // 配置useScrollTrigger
  // target: 监听的滚动元素
  // threshold: 滚动多少距离后触发(例如,从底部向上滚动100px时显示)
  const showSticky = useScrollTrigger({
    target: scrollTargetNode, // 使用state中保存的DOM节点
    disableHysteresis: true, // 禁用滞后,滚动一超过阈值就触发
    threshold: 100, // 滚动距离父容器底部100px时触发
  });

  // ... 渲染逻辑
}

这里threshold: 100的含义是:当滚动位置超过其父容器的顶部(或从顶部开始计算)100像素时,showSticky变为true。为了实现“在父容器底部时隐藏”,我们需要调整threshold的逻辑,或者更直接地,判断父容器是否滚动到了底部。

然而,useScrollTrigger的threshold默认是基于从顶部滚动的距离。如果我们想在滚动到父容器底部时隐藏,那么useScrollTrigger可能不是最直观的工具,因为它主要用于监听从顶部开始的滚动距离。

Artbreeder
Artbreeder

创建令人惊叹的插画和艺术

下载

更准确的思路是: showSticky为true时,表示用户已经向下滚动了一段距离(超过threshold)。如果我们想在父容器滚动到底部时隐藏粘性元素,那么showSticky应该控制粘性元素的显示,即当showSticky为true时显示,当showSticky为false时(在顶部或者在底部)隐藏。

让我们重新思考threshold的设定。如果threshold设为100,意味着当从父容器顶部向下滚动超过100px时,showSticky变为true。这可以用来控制当用户开始滚动时显示粘性元素,而在顶部时隐藏。

为了实现“在父容器底部时隐藏”,我们可以利用useScrollTrigger的返回值来控制粘性元素的条件渲染或者样式

当showSticky为true时,粘性元素显示。当showSticky为false时,粘性元素隐藏。 那么,threshold的设置就决定了何时showSticky变为true。如果我们将threshold设置为一个较小的值(例如1),那么只要用户开始滚动,showSticky就变为true。当用户滚动到顶部时,showSticky变为false。

但我们想要的是:当滚动到父容器底部时,粘性元素隐藏。 useScrollTrigger本身没有直接提供“滚动到元素底部”的判断。我们需要结合scrollTargetNode的scrollHeight、clientHeight和scrollTop属性来手动判断是否到达底部。

优化方案:结合useScrollTrigger和手动滚动判断

import React from 'react';
import { Box, useScrollTrigger } from '@mui/material';

export default function StickyDivControl() {
  const parentRef = React.useRef(null);
  const [scrollTargetNode, setScrollTargetNode] = React.useState(undefined);
  const [isAtBottom, setIsAtBottom] = React.useState(false);

  React.useEffect(() => {
    setScrollTargetNode(parentRef.current);
  }, []);

  // useScrollTrigger在这里可以用于判断是否在顶部
  const isScrollingDown = useScrollTrigger({
    target: scrollTargetNode,
    disableHysteresis: true,
    threshold: 1, // 只要滚动超过1px就触发
  });

  // 监听父容器的滚动事件来判断是否到达底部
  React.useEffect(() => {
    const parentElement = parentRef.current;
    if (!parentElement) return;

    const handleScroll = () => {
      const { scrollTop, scrollHeight, clientHeight } = parentElement;
      // 当滚动到底部时,scrollTop + clientHeight === scrollHeight
      // 留一点裕量,防止浮点数误差
      const bottomReached = scrollTop + clientHeight >= scrollHeight - 5;
      setIsAtBottom(bottomReached);
    };

    parentElement.addEventListener('scroll', handleScroll);
    // 初始加载时也检查一次
    handleScroll(); 

    return () => {
      parentElement.removeEventListener('scroll', handleScroll);
    };
  }, [scrollTargetNode]); // 依赖scrollTargetNode,确保在节点可用时才添加监听器

  // 粘性元素是否应该显示:
  // 1. 正在向下滚动 (isScrollingDown为true)
  // 2. 并且没有滚动到父容器底部 (isAtBottom为false)
  const shouldShowSticky = isScrollingDown && !isAtBottom;

  return (
    
      
    {Array.from({ length: 100 }, (_, index) => (
  • {`Text ${index + 1}`}
  • ))}
{/* 根据shouldShowSticky的值条件渲染粘性元素 */} {shouldShowSticky && ( 当父容器滚动到底部时隐藏我 )}
); }

在这个优化方案中:

  • useScrollTrigger用于判断用户是否已经开始向下滚动(即不在顶部)。
  • 一个独立的useEffect监听父容器的scroll事件,并计算scrollTop + clientHeight是否接近scrollHeight来判断是否到达底部。
  • shouldShowSticky结合这两个状态:只有当用户正在滚动(非顶部)并且没有到达底部时,粘性元素才显示。

完整代码示例

下面是一个完整的React组件示例,展示了如何实现当父容器滚动到底部时,粘性元素自动隐藏的功能。

import React from 'react';
import { Box, useScrollTrigger, Typography } from '@mui/material';

export default function StickyDivWithDynamicHide() {
  const parentRef = React.useRef(null);
  const [scrollTargetNode, setScrollTargetNode] = React.useState(undefined);
  const [isAtBottom, setIsAtBottom] = React.useState(false);

  // 1. 在组件挂载后,将ref.current赋值给state,作为useScrollTrigger的target
  React.useEffect(() => {
    setScrollTargetNode(parentRef.current);
  }, []);

  // 2. 使用useScrollTrigger判断是否已经开始向下滚动(离开顶部)
  // threshold: 1 表示只要滚动超过1px就触发,即离开顶部
  const isScrollingDown = useScrollTrigger({
    target: scrollTargetNode,
    disableHysteresis: true, // 禁用滞后,滚动一超过阈值就触发
    threshold: 1, 
  });

  // 3. 监听父容器的滚动事件,判断是否到达底部
  React.useEffect(() => {
    const parentElement = parentRef.current;
    if (!parentElement) return;

    const handleScroll = () => {
      const { scrollTop, scrollHeight, clientHeight } = parentElement;
      // 判断是否到达底部,留一点误差裕量
      const bottomReached = scrollTop + clientHeight >= scrollHeight - 5;
      setIsAtBottom(bottomReached);
    };

    parentElement.addEventListener('scroll', handleScroll);
    // 初始加载时也检查一次,以防内容不足无法滚动
    handleScroll(); 

    return () => {
      parentElement.removeEventListener('scroll', handleScroll);
    };
  }, [scrollTargetNode]); // 依赖scrollTargetNode,确保在节点可用时才添加监听器

  // 4. 决定粘性元素是否显示:
  // 只有当用户正在向下滚动(离开顶部)并且没有到达父容器底部时,才显示粘性元素。
  const shouldShowSticky = isScrollingDown && !isAtBottom;

  return (
    
      滚动内容区域
      
        请向下滚动,观察底部粘性元素的行为。
      
      
    {/* 生成大量内容使父容器可滚动 */} {Array.from({ length: 100 }, (_, index) => (
  • {`列表项 ${index + 1}`}
  • ))}
区域底部内容 这是父容器底部的额外内容,当滚动到这里时,粘性元素会隐藏。 {/* 根据shouldShowSticky的值条件渲染粘性元素 */} {shouldShowSticky && ( 我是一个粘性元素,滚动到底部时会消失! )}
); }

关键点与注意事项

  1. useRef与useState结合使用: useScrollTrigger的target属性需要一个DOM元素。由于ref.current在组件挂载前为null,直接传递会报错。通过useState保存ref.current并在useEffect中更新,可以确保在useScrollTrigger使用时target已是有效的DOM节点。
  2. threshold参数: 在本例中,useScrollTrigger的threshold: 1用于判断用户是否已经离开了滚动容器的顶部。如果你希望粘性元素在滚动了一定距离后才显示,可以调整这个值。
  3. 手动滚动判断: useScrollTrigger主要关注从顶部开始的滚动距离。要判断是否到达容器底部,需要手动监听scroll事件,并计算scrollTop + clientHeight >= scrollHeight。这里加入了- 5的裕量,是为了处理不同浏览器或设备上可能存在的浮点数计算误差。
  4. disableHysteresis: 设置为true可以使useScrollTrigger在滚动超过threshold时立即触发,没有延迟或“滞后”效果,使得交互更即时。
  5. 条件渲染: 使用shouldShowSticky && (...)进行条件渲染,比通过CSS display: none或visibility: hidden隐藏元素更彻底,因为它直接控制了DOM节点的存在与否。这对于不需要在DOM中保留的元素来说,通常是更优的选择。
  6. zIndex: 确保粘性元素的zIndex足够高,以防止被其他内容覆盖。
  7. 父容器样式: 父容器必须有固定的height和overflow: 'auto'或overflow: 'scroll',才能使其内部内容可滚动。

总结

通过巧妙地结合MUI的useScrollTrigger、React的useRef和useEffect,并辅以对DOM滚动属性的监听,我们可以精确控制粘性元素在父容器内的显示与隐藏逻辑。这种方法不仅解决了特定场景下的交互需求,也展示了React Hooks在处理复杂UI状态和DOM交互时的强大灵活性。理解并运用这些技术,能够帮助开发者创建更加动态和用户友好的MUI应用。

相关专题

更多
css
css

css是层叠样式表,用来表现HTML或XML等文件样式的计算机语言,不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。php中文网还为大家带来html的相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

521

2023.06.15

css居中
css居中

css居中:1、通过“margin: 0 auto; text-align: center”实现水平居中;2、通过“display:flex”实现水平居中;3、通过“display:table-cell”和“margin-left”实现居中。本专题为大家提供css居中的相关的文章、下载、课程内容,供大家免费下载体验。

262

2023.07.27

css如何插入图片
css如何插入图片

cssCSS是层叠样式表(Cascading Style Sheets)的缩写。它是一种用于描述网页或应用程序外观和样式的标记语言。CSS可以控制网页的字体、颜色、布局、大小、背景、边框等方面,使得网页的外观更加美观和易于阅读。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

753

2023.07.28

css超出显示...
css超出显示...

在CSS中,当文本内容超出容器的宽度或高度时,可以使用省略号来表示被隐藏的文本内容。本专题为大家提供css超出显示...的相关文章,相关教程,供大家免费体验。

539

2023.08.01

css字体颜色
css字体颜色

CSS中,字体颜色可以通过属性color来设置,用于控制文本的前景色,字体颜色在网页设计中起到很重要的作用,具有以下表现作用:1、提升可读性;2、强调重点信息;3、营造氛围和美感;4、用于呈现品牌标识或与品牌形象相符的风格。

757

2023.08.10

什么是css
什么是css

CSS是层叠样式表(Cascading Style Sheets)的缩写,是一种用于描述网页(或其他基于 XML 的文档)样式与布局的标记语言,CSS的作用和意义如下:1、分离样式和内容;2、页面加载速度优化;3、实现响应式设计;4、确保整个网站的风格和样式保持统一。

604

2023.08.10

css三角形怎么写
css三角形怎么写

CSS可以通过多种方式实现三角形形状,本专题为大家提供css三角形怎么写的相关教程,大家可以免费体验。

560

2023.08.21

css设置文字颜色
css设置文字颜色

CSS(层叠样式表)可以用于设置文字颜色,这样做有以下好处和优势:1、增加网页的可视化效果;2、突出显示某些重要的信息或关键字;3、增强品牌识别度;4、提高网页的可访问性;5、引起不同的情感共鸣。

389

2023.08.22

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 2.9万人学习

CSS教程
CSS教程

共754课时 | 19万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号