admin管理员组文章数量:1295066
Given the very simple page (having assumed React and react-router@4 have been imported):
// Current location: example/about
<Link to="/about/#the-team">See the team</Link>
// ... loads of content ... //
<a id="the-team"></a>
I would expect the above, upon clicking "See the team" would scroll down to the id'ed team anchor. The url correctly updates to: example/about#the-team
, but it doesn't scroll down.
I have tried alternatives such as <a name="the-team"></a>
but I believe this is no longer spec (nor does it work).
There are plenty of work arounds on github for react-router@v2 but they rely on the update callback present on BrowserRouter that is no longer present in v4.
Given the very simple page (having assumed React and react-router@4 have been imported):
// Current location: example.com/about
<Link to="/about/#the-team">See the team</Link>
// ... loads of content ... //
<a id="the-team"></a>
I would expect the above, upon clicking "See the team" would scroll down to the id'ed team anchor. The url correctly updates to: example.com/about#the-team
, but it doesn't scroll down.
I have tried alternatives such as <a name="the-team"></a>
but I believe this is no longer spec (nor does it work).
There are plenty of work arounds on github for react-router@v2 but they rely on the update callback present on BrowserRouter that is no longer present in v4.
Share Improve this question edited Nov 26, 2016 at 5:04 Chris asked Oct 24, 2016 at 11:46 ChrisChris 58.1k33 gold badges157 silver badges196 bronze badges 8- Here did you try this? github.com/rafrex/react-router-hash-link-scroll which depends upon the browser history,if it solves your problem i'll update my answer – Pritish Vaidya Commented Oct 30, 2016 at 5:45
- Looks like it relies on react router @v2 ? – Chris Commented Oct 30, 2016 at 5:59
- try if it works,maybe as it depends only on the browserHistory,to redirect to the following hash – Pritish Vaidya Commented Oct 30, 2016 at 7:57
- The issue being that React Router v4 doesn't have onUpdate callbacks – Chris Commented Oct 30, 2016 at 8:29
- oh ok i'll try to figure out something else – Pritish Vaidya Commented Oct 30, 2016 at 8:32
3 Answers
Reset to default 17 +100Given a <ScrollIntoView>
component which takes the id of the element to scroll to:
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
}
}
You could either wrap the contents of your view component in it:
const About = (props) => (
<ScrollIntoView id={props.location.hash}>
// ...
</ScrollIntoView>
)
Or you could create a match wrapper:
const MatchWithHash = ({ component:Component, ...props }) => (
<Match {...props} render={(props) => (
<ScrollIntoView id={props.location.hash}>
<Component {...props} />
</ScrollIntoView>
)} />
)
The usage would be:
<MatchWithHash pattern='/about' component={About} />
A fully fleshed out solution might need to consider edge cases, but I did a quick test with the above and it seemed to work.
Edit:
This component is now available through npm. GitHub: https://github.com/pshrmn/rrc
npm install --save rrc
import { ScrollIntoView } from 'rrc'
The react-router team seem to be actively tracking this issue (at the time of writing v4 isn't even fully released).
As a temporary solution, the following works fine.
EDIT 3 This answer can now be safely ignored with the accepted answer in place. Left as it tackles the question slightly differently.
EDIT2 The following method causes other issues, including but not limited to, clicking Section A, then clicking Section A again doesn't work. Also doesn't appear to work with any kind of animation (have a feeling with animation starts, but is overwritten by a later state change)
EDIT Note the following does screw up the Miss component. Still looking for a more robust solution
// 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>
Then, the HashWatcher component would look like the following. It is the temp component that "listens" for all route changes
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;
}
}
I've created a library called react-scroll-manager that addresses this issue and the other issues around scroll position with React Router. It uses this technique to navigate to hash links anywhere in the document without the need to wrap them individually. Simply wrap your Router component in a ScrollManager component:
class App extends React.Component {
constructor() {
super();
this.history = createHistory();
}
render() {
return (
<ScrollManager history={this.history}>
<Router history={this.history}>
...
</Router>
</ScrollManager>
);
}
}
You can link to any component with an id
property:
<MyComponent id="mycomp">...</MyComponent>
Just include the id
as a fragment in your Link target:
<Link to="#mycomp">...</Link>
The library is based on HTML5 and React 16, and it supports React Router 4 (and possibly earlier versions).
本文标签: javascriptIn react router v4 how does one link to a fragment identifierStack Overflow
版权声明:本文标题:javascript - In react router v4 how does one link to a fragment identifier? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738447661a2087305.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论