持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
前言
在这篇文章中(实验:揣测浏览器history下的滚动条处理),我们测试了浏览器历史记录前进后退的一些行为,这次我们来测试react路由history模式下滚动条处理,我们知道路由模式无非是基于hash和history两种模式,通过监听其对应的行为而做出页面的更改。
以history模式为例,主要是通过window.history这个api监听浏览器地址的变化,我们也知道,在浏览器当前页新开一个页面,通过history触发的行为称为push,而前进后退则称为pop。主要是因为history维护的是一个地址栈。
在上一篇中我们测试了在浏览器 history触发push的行为滚动条是不会变化的,push地址出现的现象是地址改变了,而实际上页面并没有做出更改的行为。当新push的页面改变原本的dom结构,是否会触发滚动位置的复用呢?
实验
这里我们以react-router-dom的v5版本进行测试。
yarn add react-router-dom@5.0.0
在路由使用之前,我们需要处理高版本react使用v5路由失效的问题,处理方法是把包裹根节点的组件 React.StrictMode删除掉,宽松策略下就可以使用当前路由。
下面是页面的基本配置:
//App页面
function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path='/' component={Home} exact></Route>
<Route path="/a" component={A} exact></Route>
<Route path="/b" component={B} exact></Route>
<Route path="/c" component={C} exact></Route>
</Switch>
</Router>
</div>
);
}
//Home组件
function Home(){
return <>
<Link to='/a'>A</Link>
<Link to='/b'>B</Link>
<Link to='/c'>C</Link>
</>
}
当我们点击A跳转到/a页面,下面是A页面的代码,而此时A页面的高度是存在滚动条的。(后续页面的结构都是和A组件一样,只是更改了背景或者高度)
//A组件
function A() {
return (
<div style={{
background: 'green',
}}>
<div style={{
width: '500px',
height: '500px',
backgroundColor: 'green'
}}>
</div>
<Link to='/b'>B</Link>
<div style={{
width: '500px',
height: '500px',
backgroundColor: '#008c8c'
}}>
</div>
<div style={{
width: '500px',
height: '500px',
backgroundColor: 'green'
}}>
</div>
</div>
)
}
当我们跳转到A页面时,此时滚动条是置顶的行为。
当我们下滑A页面到一定的滚动位置时,我们点击跳转到B页面,此时B页面并不会置顶,而是复用了A页面的滚动位置。
我们点击跳转到C页面,此时页面仍然复用了B页面的位置。我们将C页面滚动到底部。
此时我们回退页面、前进页面,发现滚动条的位置是被记录的。而网络面板中并不存在页面的请求。
结合上一篇记录的现象,我们初步得出这样的规律:
- 因为路由模式下都是在同一个html页面,所以历史记录的前进回退并不会导致页面的重新请求。
- 往地址栏push一个地址,浏览器是会复用上一个页面的滚动位置的,除非新开的页面没有滚动条。
此时我们可以验证一种猜想,当新开的页面高度比上一个页面小呢,经过测试发现,滚动条是移动到底部。
如果新开的页面一开始是没有滚动条的,经过数据请求之后出现了滚动条,滚动条是否会复用呢?
验证这个猜想,我们通过计时器模拟:
function C() {
const [list, setList] = useState([])
useEffect(() => {
setTimeout(() => {
setList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
}, 1000)
}, [])
return (
<div style={{
background: 'green',
}}>
<div style={{
width: '500px',
height: '100px',
backgroundColor: 'yellow'
}}>
</div>
<Link to='/a'>a</Link>
<div style={{
width: '500px',
height: '100px',
backgroundColor: '#008c8c'
}}>
</div>
<div style={{
width: '500px',
height: '100px',
backgroundColor: 'yellow'
}}>
</div>
{list.map((item, index) => <div key={index} style={{ width: '100px', height: '100px', background: 'green' }}>
{item}
</div>)}
</div>
)
}
测试结果发现初始界面没有滚动条,经过数据请求之后页面高度足以存在滚动条了,可是滚动条是置顶的。
我们通过调整页面的初始高度,使得初始页面是存在滚动条的,我们再把数据请求改成持续性的setInterval计时器,每次增加一点点页面高度。我们发现页面会记录上次滚动条的位置,一开始页面会在底部,随着页面高度的增长,滚动条也随着滚动,直到滚动到上一个页面的滚动条位置时才停止滚动。
结论
以下的结论基于v5路由。
- 新push的页面滚动条位置会继承上一次页面滚动条位置,如果位置不够,到就最底部
- 浏览器前进后退都能记录之前的滚动条记录
- history的跳转,继第一条现象,当后续往页面插入内容时,滚动条仍然会往下滚动,直到停到上一个页面离开时的滚动位置。(条件,跳转的页面存在滚动条)
- history的跳转,继第一条现象,当后续往页面插入内容时,滚动条不会往下滚动,会置顶。(条件,跳转的页面不存在滚动条)