目录
- 1,滚动条复位
- [2,在 React 中的触发的3种方式](#2,在 React 中的触发的3种方式)
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>
);
}
以上。