San*_*cho 9 javascript scrollview reactjs react-router-v4 react-router-dom
我有两个<Route>
用react-router创建的.
当用户点击"返回列表"时,我想滚动用户在列表中的位置.
我怎样才能做到这一点?
Roy*_*ers 14
在codesandbox的工作示例
React Router v4不提供开箱即用的滚动恢复支持,因为它目前支持它们也不会.在React Router V4部分- 滚动恢复其文档中,您可以阅读更多相关信息.
因此,每个开发人员都需要编写逻辑来支持这一点,尽管我们确实有一些工具可以帮助实现这一目标.
.scrollIntoView()
可以在一个元素上调用,正如你猜测的那样,它会将其滚动到视图中.支持非常好,目前,93.33%的浏览器支持它.资料来源:icanuse
<Link />
组件可以通过对状态React Router的Link组件有一个to
prop,你可以提供一个对象而不是一个字符串.这是谁的样子.
<Link to={{ pathname: '/card', state: 9 }}>Card nine</Link>
Run Code Online (Sandbox Code Playgroud)
我们可以使用state将信息传递给将要呈现的组件.在这个例子中,状态被分配了一个数字,这足以回答你的问题,稍后你会看到,但它可以是任何东西.路径/card
渲染<Card />
现在可以在props.location.state访问变量状态,我们可以按照自己的意愿使用它.
渲染各种卡时,我们为每个卡添加一个唯一的类.通过这种方式,我们可以传递一个标识符,并且当我们导航回卡列表概述时,我们知道该项需要滚动到视图中.
<Cards />
呈现一个列表,每个项目都有一个唯一的类;Link />
将唯一标识符传递给<Card />
;<Card />
呈现卡片详细信息和带有唯一标识符的后退按钮;<Cards />
安装后,.scrollIntoView()
滚动到之前使用数据单击的项目props.location.state
.以下是各部分的一些代码片段.
// Cards component displaying the list of available cards.
// Link's to prop is passed an object where state is set to the unique id.
class Cards extends React.Component {
componentDidMount() {
const item = document.querySelector(
".restore-" + this.props.location.state
);
if (item) {
item.scrollIntoView();
}
}
render() {
const cardKeys = Object.keys(cardData);
return (
<ul className="scroll-list">
{cardKeys.map(id => {
return (
<Link
to={{ pathname: `/cards/${id}`, state: id }}
className={`card-wrapper restore-${id}`}
>
{cardData[id].name}
</Link>
);
})}
</ul>
);
}
}
// Card compoment. Link compoment passes state back to cards compoment
const Card = props => {
const { id } = props.match.params;
return (
<div className="card-details">
<h2>{cardData[id].name}</h2>
<img alt={cardData[id].name} src={cardData[id].image} />
<p>
{cardData[id].description} <a href={cardData[id].url}>More...</a>
</p>
<Link
to={{
pathname: "/cards",
state: props.location.state
}}
>
<button>Return to list</button>
</Link>
</div>
);
};
// App router compoment.
function App() {
return (
<div className="App">
<Router>
<div>
<Route exact path="/cards" component={Cards} />
<Route path="/cards/:id" component={Card} />
</div>
</Router>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)
由于没有关于如何在功能组件中执行此操作的答案,因此这是我为项目实现的挂钩解决方案:
import React from 'react';
import { useHistory } from 'react-router-dom';
function useScrollMemory(): void {
const history = useHistory<{ scroll: number } | undefined>();
React.useEffect(() => {
const { push, replace } = history;
// Override the history PUSH method to automatically set scroll state.
history.push = (path: string) => {
push(path, { scroll: window.scrollY });
};
// Override the history REPLACE method to automatically set scroll state.
history.replace = (path: string) => {
replace(path, { scroll: window.scrollY });
};
// Listen for location changes and set the scroll position accordingly.
const unregister = history.listen((location, action) => {
window.scrollTo(0, action !== 'POP' ? 0 : location.state?.scroll ?? 0);
});
// Unregister listener when component unmounts.
return () => {
unregister();
};
}, [history]);
}
function App(): JSX.Element {
useScrollMemory();
return <div>My app</div>;
}
Run Code Online (Sandbox Code Playgroud)
使用此覆盖解决方案,您无需担心在所有Link
元素中传递状态。一项改进是使其通用,以便它向后兼容push
和 的replace
方法history
,但在我的特定情况下这不是必需的,所以我省略了它。
我正在使用react-router-dom
,但您也可以轻松地覆盖普通历史 API 的方法。
归档时间: |
|
查看次数: |
4828 次 |
最近记录: |