React@16.x(43)路由v5.x(8)常见应用场景(5)- 滚动条复位

目录

1,滚动条复位

因为切换路由,页面并不会刷新,所以需要手动复位滚动条。实现滚动条复位是比较简单的,注意点在于 React 中的触发时机。

滚动条复位实现逻辑:resetScroll.js

js 复制代码
let timer1, timer2;

export default function resetScroll() {
    // 先清理,是因为当切换路由后,滚动动画还没有完成时,又切换了路由。此时需要重新开始动画。
    clearInterval(timer1);
    clearInterval(timer2);
    const html = document.documentElement;
    timer1 = animate(html.scrollTop, 0, (value) => {
        html.scrollTop = value;
    });
    timer2 = animate(html.scrollLeft, 0, (value) => {
        html.scrollLeft = value;
    });
}

/**
 * @param {*} start 滚动起始点
 * @param {*} end 滚动终点(0)
 * @param {*} callback 计时器每次触发的函数,会传递最新的滚动距离。
 * @param {*} totalTime 滚动总时间
 * @returns
 */
function animate(start, end, callback, totalTime = 100) {
    const tick = 16;
    const times = Math.ceil(totalTime / 16); // 变化次数
    const distance = (start - end) / times; // 每次运动的距离
    let curTimes = 0;
    let timer = setInterval(() => {
        curTimes++;
        start -= distance;
        if (curTimes >= times) {
            clearInterval(timer);
            start = end;
        }
        callback(start);
    }, tick);
    return timer;
}

2,在 React 中的触发的3种方式

2.1,高阶组件

对类组件使用高阶组件封装,并在返回的类组件中的 componentDidMount() 中调用 resetScroll() 即可。不多赘述。

2.2,useEffect

定义一个依赖项为 pathname 的 HOOK 函数,并在目标路由组件中执行即可。

js 复制代码
function useScroll(pathname) {
    useEffect(() => {
        resetScroll();
    }, [pathname]);
}

App.jsx

js 复制代码
import { BrowserRouter as Router, Route, NavLink } from "react-router-dom";
import { useScroll } from "./hooks";
import "./App.css";

function News(props) {
    useScroll(props.location.pathname);
    return <div className="page news">News</div>;
}

function Goods(props) {
    useScroll(props.location.pathname);
    return <div className="page goods">Goods</div>;
}

export default function App() {
    return (
        <div className="container">
            <Router>
                <div className="nav-box">
                    <NavLink to="/news">新闻页</NavLink>
                    <NavLink to="/goods">商品页</NavLink>
                </div>
                <div className="page-box">
                    <Route path="/news" component={News}></Route>
                    <Route path="/goods" component={Goods}></Route>
                </div>
            </Router>
        </div>
    );
}

App.css

css 复制代码
.nav-box {
    position: fixed;
    top: 0;
    margin: 0 auto;
    height: 50px;
}

.nav-box a {
    display: inline-block;
    margin: 10px;
}

.nav-box a.active {
    color: salmon;
}

.page-box {
    margin-top: 50px;
}

.page {
    height: 150vh;
    width: 150vh;
}

.page.news {
    background-color: lightgreen;
}

.page.goods {
    background-color: lightyellow;
}

2.3,路由守卫

上篇文章中介绍了路由守卫。

所以可在路由发生变化时执行 resetScroll() 即可。

js 复制代码
export default function App() {
    return (
        <div className="container">
            <RouteGuard
                onRouteChange={(prevLocation, nextLocation) => {
                    // 因为点击相同路由也会执行,所以增加判断。
                    if (prevLocation.pathname !== nextLocation.nextLocation) {
                        resetScroll();
                    }
                }}
            >
                {/* ... */}
            </RouteGuard>
        </div>
    );
}

以上。

相关推荐
程序员大阳9 分钟前
HTML+CSS+JS对话式实战(6)-学生端查看活动功能开发
javascript·css·html·模块·查看学生
jay神31 分钟前
基于 YOLOv8 的轴承缺陷检测(Web 版)
前端·人工智能·yolo
jay神39 分钟前
基于 YOLOv8 的森林火灾检测系统(Web 版)
前端·yolo
code2cat44 分钟前
HTML基础篇之第一张网页:从index.html到浏览器里的任务清单
前端·html
miss1 小时前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan2 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真2 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment2 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan2 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么2 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模