React Router v4 - 切换组件时保持滚动位置 [英] React Router v4 - Keep scrolling position when switching components

查看:66
本文介绍了React Router v4 - 切换组件时保持滚动位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用 react-router 创建了两个 .

  • /cards -> 纸牌游戏列表
  • /cards/1 -> 纸牌游戏 #1 的详细信息

当用户点击返回列表"时,我想将用户滚动到他在列表中的位置.

我该怎么做?

解决方案

codesandbox

React Router v4 不提供对滚动恢复的开箱即用支持,而且就目前而言,它们也不会.在他们文档的 React Router V4 - Scroll Restoration 部分中,您可以阅读更多内容关于它.

因此,每个开发人员都需要编写支持此功能的逻辑,但我们确实有一些工具可以实现这一点.

element.scrollIntoView()

.scrollIntoView() 可以在一个元素上调用,你可以猜到,它会将它滚动到视图中.支持很好,目前97%的浏览器都支持.来源:icanuse

组件可以传递状态

React Router 的 Link 组件有一个 to 属性,你可以提供一个对象而不是字符串.这就是这个样子.

<Link to={{ pathname: '/card', state: 9 }}>卡片九</Link>

我们可以使用 state 将信息传递给将要呈现的组件.在这个例子中, state 被分配了一个数字,它足以回答你的问题,稍后你会看到,但它可以是任何东西.路由 /card 渲染 将可以访问 props.location.state 处的变量状态,我们可以使用如我们所愿.

标记每个列表项

在渲染各种卡片时,我们为每张卡片添加一个独特的类.这样我们就有了一个标识符,我们可以传递它,并知道当我们导航回卡片列表概览时需要将此项滚动到视图中.

解决方案

  1. 呈现一个列表,每个项目都有一个唯一的类;
  2. 当一个项目被点击时,Link/> 将唯一标识符传递给 ;
  3. 呈现卡片详细信息和带有唯一标识符的后退按钮;
  4. 当按钮被点击并且 被挂载时,.scrollIntoView() 使用 .scrollIntoView() 滚动到之前点击的项目代码>props.location.state.

以下是各个部分的一些代码片段.

//Cards 组件显示可用卡片的列表.//链接到 prop 传递一个对象,其中状态设置为唯一 id.class Cards 扩展了 React.Component {componentDidMount() {const item = document.querySelector(".restore-" + this.props.location.state);如果(项目){item.scrollIntoView();}}使成为() {const cardKeys = Object.keys(cardData);返回 (<ul className="滚动列表">{cardKeys.map(id => {返回 (<链接to={{ 路径名:`/cards/${id}`,状态:id }}className={`card-wrapper restore-${id}`}>{cardData[id].name}</链接>);})});}}//卡片组件.链接组件将状态传递回卡片组件const Card = props =>{const { id } = props.match.params;返回 (<div className="card-details"><h2>{cardData[id].name}</h2><img alt={cardData[id].name} src={cardData[id].image}/><p>{cardData[id].description}&nbsp;<a href={cardData[id].url}>更多...</a></p><链接到={{路径名:"/cards",状态:props.location.state}}><button>返回列表</button></链接>

);};//应用路由器组件.功能应用(){返回 (<div className="应用程序"><路由器><div><路由精确路径="/cards" component={Cards}/><Route path="/cards/:id" component={Card}/>

</路由器>

);}const rootElement = document.getElementById("root");ReactDOM.render(, rootElement);

I have two <Route>s created with react-router.

  • /cards -> List of cards game
  • /cards/1 -> Detail of card game #1

When the user clicks on the "Return to list", I want to scroll the user where he was on the list.

How can I do this?

解决方案

Working example at codesandbox

React Router v4 does not provide out of the box support for scroll restoration and as it currently stands they won't either. In section React Router V4 - Scroll Restoration of their docs you can read more about it.

So, it's up to every developer to write logic to support this although, we do have some tools to make this work.

element.scrollIntoView()

.scrollIntoView() can be called on an element and as you can guess, it scrolls it into view. Support is quite good, currently, 97% of browsers support it. Source: icanuse

The <Link /> component can pass on state

React Router's Link component has a to prop which you can provide an object instead of a string. Here's who this looks.

<Link to={{ pathname: '/card', state: 9 }}>Card nine</Link>

We can use state to pass on information to the component that will be rendered. In this example, state is assigned a number, which will suffice in answering your question, you'll see later, but it can be anything. The route /card rendering <Card /> will have access to the variable state now at props.location.state and we can use it as we wish.

Labeling each list item

When rendering the various cards, we add a unique class to each one. This way we have an identifier that we can pass on and know that this item needs to be scrolled into view when we navigate back to the card list overview.

Solution

  1. <Cards /> renders a list, each item with a unique class;
  2. When an item is clicked, Link /> passes the unique identifier to <Card />;
  3. <Card /> renders card details and a back button with the unique identifier;
  4. When the button is clicked, and <Cards /> is mounted, .scrollIntoView() scrolls to the item that was previously clicked using the data from props.location.state.

Below are some code snippets of various parts.

// 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}&nbsp;<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);

这篇关于React Router v4 - 切换组件时保持滚动位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆