如何实现高度与页面Y轴滚动坐标关联的动态自定义滚动条
实现方案
核心逻辑
- 计算页面最大可滚动距离:
document.documentElement.scrollHeight - window.innerHeight,即页面总高度减去视口高度,为用户可滚动的总范围 - 监听全局滚动事件,用当前滚动距离除以最大可滚动距离得到滚动进度百分比
- 将进度百分比作为props传递给styled组件,动态控制内层滚动条的高度
1. 调整样式组件代码
修改DynamicScrollbar的高度取值,从组件props中获取动态进度:
import styled from 'styled-components'; export const DynamicScrollbarContainer = styled.div` position: fixed; right: 5%; top: 35%; width: 2px; height: 300px; background-color: rgba(255,255,255,0.5); @media ${(props) => props.theme.breakpoints.xl} { display: none; } `; export const DynamicScrollbar = styled.div` width: 100%; height: ${props => props.scrollProgress || 0}%; background-color: #ffffff; transition: height 0.1s ease; // 可选,添加过渡让高度变化更流畅 `
2. 调整组件逻辑代码
添加滚动事件监听、进度计算逻辑,注意组件卸载时清理事件监听避免内存泄漏:
import React, { useState, useEffect } from 'react'; import { DynamicScrollbarContainer, DynamicScrollbar } from './ScrollbarStyles'; const ScrollBar = () => { const [scrollProgress, setScrollProgress] = useState(0); // 节流定时器标识 let scrollTimer = null; const handleScroll = () => { // 200ms节流,减少触发频率 if (scrollTimer) return; scrollTimer = setTimeout(() => { // 计算总可滚动高度 const totalScrollableHeight = document.documentElement.scrollHeight - window.innerHeight; // 页面内容不足一屏时特殊处理 if (totalScrollableHeight <= 0) { setScrollProgress(100); scrollTimer = null; return; } // 计算进度百分比 const progress = (window.scrollY / totalScrollableHeight) * 100; setScrollProgress(progress); scrollTimer = null; }, 200); }; useEffect(() => { // 组件挂载时添加监听,同时触发一次计算初始进度 window.addEventListener('scroll', handleScroll); handleScroll(); // 组件卸载时移除监听 return () => { window.removeEventListener('scroll', handleScroll); if (scrollTimer) clearTimeout(scrollTimer); }; }, []); return ( <DynamicScrollbarContainer> <DynamicScrollbar scrollProgress={scrollProgress} /> </DynamicScrollbarContainer> ); }; export default ScrollBar;
可选适配说明
如果是监听局部容器的滚动而非页面全局滚动,只需要做以下调整:
- 将监听对象从
window替换为对应滚动容器的DOM节点 - 滚动距离取值从
window.scrollY替换为容器的scrollTop属性 - 总高度取值从
document.documentElement.scrollHeight替换为容器的scrollHeight属性 - 视口高度取值从
window.innerHeight替换为容器的clientHeight属性
内容的提问来源于stack exchange,提问作者giosan
相关产品推荐
相关产品推荐

