使用带反应路由器的锚点
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用带反应路由器的锚点相关的知识,希望对你有一定的参考价值。
如何使用react-router,并将链接导航到特定页面上的特定位置? (例如/home-page#section-three
)
细节:
我在我的React app中使用react-router
。
我有一个站点范围的导航栏,需要链接到页面的特定部分,如/home-page#section-three
。
因此,即使您在/blog
上,单击此链接仍将加载主页,第三部分滚动到视图中。这正是标准<a href="/home-page#section-three>
的工作原理。
注意:react-router的创建者没有给出明确的答案。他们说它正在进行中,并且同时使用其他人的答案。我会尽力保持这个问题的最新进展和可能的解决方案,直到出现主导的问题。
研究:
How to use normal anchor links with react-router
这个问题是从2015年(所以10年前的反应时间)。最受欢迎的答案是使用HistoryLocation
而不是HashLocation
。基本上这意味着将位置存储在窗口历史记录中,而不是存储在哈希片段中。
坏消息是......即使使用HistoryLocation(大多数教程和文档在2016年所说的内容),锚标签仍然不起作用。
https://github.com/ReactTraining/react-router/issues/394
ReactTraining上的一个线程,关于如何使用anchor链接与react-router。这是没有确认的答案。请注意,因为大多数建议的答案都已过时(例如使用<Link>
中的“hash”道具)
这是我找到的一个解决方案(2016年10月)。它是跨浏览器兼容的(在ie,ff,chrome,mobile safari,safari中测试)。
您可以为您的路由器提供onUpdate
属性。只要路由更新,就会调用此方法。此解决方案使用onUpdate属性检查是否存在与哈希匹配的DOM元素,然后在路由转换完成后滚动到该元素。
您必须使用browserHistory而不是hashHistory。
答案是在这个thread中的“Rafrax”。
将此代码添加到您定义<Router>
的位置:
import React from 'react';
import { render } from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';
const routes = (
// your routes
);
function hashLinkScroll() {
const { hash } = window.location;
if (hash !== '') {
// Push onto callback queue so it runs after the DOM is updated,
// this is required when navigating from a different page so that
// the element is rendered on the page before trying to getElementById.
setTimeout(() => {
const id = hash.replace('#', '');
const element = document.getElementById(id);
if (element) element.scrollIntoView();
}, 0);
}
}
render(
<Router
history={browserHistory}
routes={routes}
onUpdate={hashLinkScroll}
/>,
document.getElementById('root')
)
如果您感觉懒惰并且不想复制该代码,则可以使用仅为您定义该功能的Anchorate。 https://github.com/adjohnson916/anchorate
React Router Hash Link为我工作。易于安装和实施:
$ npm install --save react-router-hash-link
在component.js中将其导入为Link:
import { HashLink as Link } from 'react-router-hash-link';
而不是使用锚<a>
,使用<Link>
:
<Link to="home-page#section-three">Section three</Link>
注意:我使用HashRouter
而不是Router
:
只是避免使用react-router进行本地滚动:
document.getElementById('myElementSomewhere').scrollIntoView()
https://stackoverflow.com/a/40280486/515585的问题有时候,如果该部分依赖于某些异步操作,则仍会呈现或加载具有id的元素。以下函数将尝试按id查找元素并导航到它并每100ms重试一次,直到最多重试50次:
scrollToLocation = () => {
const { hash } = window.location;
if (hash !== '') {
let retries = 0;
const id = hash.replace('#', '');
const scroll = () => {
retries += 0;
if (retries > 50) return;
const element = document.getElementById(id);
if (element) {
setTimeout(() => element.scrollIntoView(), 0);
} else {
setTimeout(scroll, 100);
}
};
scroll();
}
}
另一种选择:react-scrollchor https://www.npmjs.com/package/react-scrollchor
react-scrollchor:一个React组件,用于滚动到具有平滑动画的#hash链接。 Scrollchor是Scroll和Anchor的混合体
注意:它不使用react-router
这是一个简单的解决方案,不需要任何订阅或第三方包。应该与react-router@3
及以上和react-router-dom
合作。
工作示例:https://fglet.codesandbox.io/
来源(遗憾的是,目前在编辑器中不起作用):
ScrollHandler Hook Example
import { useEffect } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";
const ScrollHandler = ({ location, children }) => {
useEffect(
() => {
const element = document.getElementById(location.hash.replace("#", ""));
setTimeout(() => {
window.scrollTo({
behavior: element ? "smooth" : "auto",
top: element ? element.offsetTop : 0
});
}, 100);
}, [location]);
);
return children;
};
ScrollHandler.propTypes = {
children: PropTypes.node.isRequired,
location: PropTypes.shape({
pathname: PropTypes.string,
search: PropTypes.string,
hash: PropTypes.string,
state: PropTypes.any,
key: PropTypes.string
}).isRequired
};
export default withRouter(ScrollHandler);
ScrollHandler Class Example
import { PureComponent } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";
class ScrollHandler extends PureComponent {
componentDidMount = () => this.handleScroll();
componentDidUpdate = prevProps => {
const { location: { pathname, hash } } = this.props;
if (
pathname !== prevProps.location.pathname ||
hash !== prevProps.location.hash
) {
this.handleScroll();
}
};
handleScroll = () => {
const { location: { hash } } = this.props;
const element = document.getElementById(hash.replace("#", ""));
setTimeout(() => {
window.scrollTo({
behavior: element ? "smooth" : "auto",
top: element ? element.offsetTop : 0
});
}, 100);
};
render = () => this.props.children;
};
ScrollHandler.propTypes = {
children: PropTypes.node.isRequired,
location: PropTypes.shape({
hash: PropTypes.string,
key: PropTypes.string,
pathname: PropTypes.string,
search: PropTypes.string,
state: PropTypes.any
})
};
export default withRouter(ScrollHandler);
我将Don P的解决方案(见上文)改编为react-router
4(2019年1月),因为onUpdate
上没有<Router>
道具了。
import React from 'react';
import * as ReactDOM from 'react-dom';
import { Router, Route } from 'react-router';
import { createBrowserHistory } from 'history';
const browserHistory = createBrowserHistory();
browserHistory.listen(location => {
const { hash } = location;
if (hash !== '') {
// Push onto callback queue so it runs after the DOM is updated,
// this is required when navigating from a different page so that
// the element is rendered on the page before trying to getElementById.
setTimeout(
() => {
const id = hash.replace('#', '');
const element = document.getElementById(id);
if (element) {
element.scrollIntoView();
}
},
0
);
}
});
ReactDOM.render(
<Router history={browserHistory}>
// insert your routes here...
/>,
document.getElementById('root')
)
以上是关于使用带反应路由器的锚点的主要内容,如果未能解决你的问题,请参考以下文章
URL中的锚点(fragment片段标识符)是什么?(hash mark(#))(HTML 页面内定位)(之前学html不是学了吗?忘啦?)(SEO 搜索引擎优化)