[英]In react router v4 how does one link to a fragment identifier?
鉴于非常简单的页面(假设已经导入了React和react-router @ 4):
// Current location: example.com/about
<Link to="/about/#the-team">See the team</Link>
// ... loads of content ... //
<a id="the-team"></a>
我希望上面的内容,点击“看到团队”后会向下滚动到id'ed团队主播。 该网址正确更新为: example.com/about#the-team
,但不会向下滚动。
我尝试过<a name="the-team"></a>
等替代方案,但我相信这不再是规范(也不适用)。
在github上有很多关于react-router @ v2的解决办法,但它们依赖于BrowserRouter上存在的更新回调,v4中不再存在。
给定一个<ScrollIntoView>
组件,它将元素的id转到:
class ScrollIntoView extends React.Component {
componentDidMount() {
this.scroll()
}
componentDidUpdate() {
this.scroll()
}
scroll() {
const { id } = this.props
if (!id) {
return
}
const element = document.querySelector(id)
if (element) {
element.scrollIntoView()
}
}
render() {
return this.props.children
}
}
您可以将视图组件的内容包装在其中:
const About = (props) => (
<ScrollIntoView id={props.location.hash}>
// ...
</ScrollIntoView>
)
或者你可以创建一个匹配包装器:
const MatchWithHash = ({ component:Component, ...props }) => (
<Match {...props} render={(props) => (
<ScrollIntoView id={props.location.hash}>
<Component {...props} />
</ScrollIntoView>
)} />
)
用法是:
<MatchWithHash pattern='/about' component={About} />
一个完全充实的解决方案可能需要考虑边缘情况,但我做了上面的快速测试,它似乎工作。
此组件现在可通过npm获得。 GitHub: https : //github.com/pshrmn/rrc
npm install --save rrc
import { ScrollIntoView } from 'rrc'
react-router团队似乎正在积极地跟踪这个问题(在撰写本文时,v4甚至还没有完全发布)。
作为临时解决方案,以下工作正常。
编辑3现在可以使用已接受的答案安全地忽略此答案。 因为它解决问题略有不同。
EDIT2以下方法导致其他问题,包括但不限于单击A部分,然后再次单击A部分不起作用。 也似乎不适用于任何类型的动画(有动画开始的感觉,但被以后的状态更改覆盖)
编辑注意以下操作搞砸了Miss组件。 仍在寻找更强大的解决方案
// App
<Router>
<div>
<Match pattern="*" component={HashWatcher} />
<ul>
<li><Link to="/#section-a">Section A</Link></li>
<li><Link to="/#section-b">Section B</Link></li>
</ul>
<Match pattern="/" component={Home} />
</div>
</Router>
// Home
// Stock standard mark up
<div id="section-a">
Section A content
</div>
<div id="section-b">
Section B content
</div>
然后,HashWatcher组件将如下所示。 正是临时组件“监听”所有路由更改
import { Component } from 'react';
export default class HashWatcher extends Component {
componentDidMount() {
if(this.props.location.hash !== "") {
this.scrollToId(this.hashToId(this.props.location.hash));
}
}
componentDidUpdate(prevProps) {
// Reset the position to the top on each location change. This can be followed up by the
// following hash check.
// Note, react-router correctly sets the hash and path, even if using HashHistory
if(prevProps.location.pathname !== this.props.location.pathname) {
this.scrollToTop();
}
// Initially checked if hash changed, but wasn't enough, if the user clicked the same hash
// twice - for example, clicking contact us, scroll to top, then contact us again
if(this.props.location.hash !== "") {
this.scrollToId(this.hashToId(this.props.location.hash));
}
}
/**
* Remove the leading # on the hash value
* @param string hash
* @return string
*/
hashToId(hash) {
return hash.substring(1);
}
/**
* Scroll back to the top of the given window
* @return undefined
*/
scrollToTop() {
window.scrollTo(0, 0);
}
/**
* Scroll to a given id on the page
* @param string id The id to scroll to
* @return undefined
*/
scrollToId(id) {
document.getElementById(id).scrollIntoView();
}
/**
* Intentionally return null, as we never want this component actually visible.
* @return {[type]} [description]
*/
render() {
return null;
}
}
我已经创建了一个名为react-scroll-manager的库,它解决了这个问题以及与React Router一起滚动位置的其他问题。 它使用此技术导航到文档中任何位置的哈希链接,而无需单独包装它们。 只需将您的Router组件包装在ScrollManager组件中:
class App extends React.Component {
constructor() {
super();
this.history = createHistory();
}
render() {
return (
<ScrollManager history={this.history}>
<Router history={this.history}>
...
</Router>
</ScrollManager>
);
}
}
您可以链接到具有id
属性的任何组件:
<MyComponent id="mycomp">...</MyComponent>
只需将id
作为片段包含在您的链接目标中:
<Link to="#mycomp">...</Link>
该库基于HTML5和React 16,它支持React Router 4(可能还有早期版本)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.