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>
    );
}

以上。

相关推荐
Data analyse4562 小时前
rnweb 回放数据量太大怎么办?分片存储与断点续传的实现思路
前端·网络·算法·数据分析
xiaogai_gai2 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库
环境栈笔记3 小时前
指纹浏览器 WebRTC 怎么设置?从 ICE 候选、代理出口到功能验证
前端·人工智能·后端·自动化
赵大仁4 小时前
官网性能优化实战:LCP 3.2s → 2.1s、CLS 0.107 → 0,以及被我推翻的 6 个判断
前端·性能优化·cls·lcp·core web vitals
xiancai_xianyu4 小时前
Text2SQL落地生产库前,SQL要过哪三道闸
前端·数据库·sql·sql注入·text2sql·ai agent开发·企业级ai框架
小羊没烦恼!4 小时前
T-SQL查询进阶--理解SQL SERVER中的分区表
服务器·开发语言·前端·javascript·html
史瓦辛格4 小时前
给 DeepSeek Harness 写费用插件:把「这次会话花了多少钱」算准
前端·deepseek
星光不问赶路人4 小时前
Vue 3 + TypeScript 中 enum 的使用实践
前端·vue.js
鸥梨菌Honevid4 小时前
UVM 中 REQ 和 RSP 类型详解:从通信模型到 item_done 与 put_response
java·前端·servlet
IT_陈寒4 小时前
Python多进程共享变量这个坑,差点让我加班到凌晨
前端·人工智能·后端