react-router:如果<Link>处于活动状态,如何禁用它?
react-router: How to disable a <Link>, if its active?
如果 URL 已经激活,我如何在 react-router 中禁用 <Link>
?例如。如果我的 URL 在点击 <Link>
时不会改变,我想完全阻止点击或呈现 <span>
而不是 <Link>
。
我想到的唯一解决方案是使用 activeClassName
(或 activeStyle
)并设置 pointer-events: none;
,但我更愿意使用适用于 IE9 的解决方案和 IE10.
我不会问您为什么想要这种行为,但我想您可以将 <Link />
包装在您自己的自定义 link 组件中。
<MyLink to="/foo/bar" linktext="Maybe a link maybe a span" route={this.props.route} />
class MyLink extends Component {
render () {
if(this.props.route === this.props.to){
return <span>{this.props.linktext}</span>
}
return <Link to={this.props.to}>{this.props.linktext}</Link>
}
}
(ES6,但你大概明白了大概意思……)
另一种可能性是,如果已在同一路径上单击,则禁用单击事件。这是 与 react-router v4 一起工作的解决方案。
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
class SafeLink extends Component {
onClick(event){
if(this.props.to === this.props.history.location.pathname){
event.preventDefault();
}
// Ensure that if we passed another onClick method as props, it will be called too
if(this.props.onClick){
this.props.onClick();
}
}
render() {
const { children, onClick, ...other } = this.props;
return <Link onClick={this.onClick.bind(this)} {...other}>{children}</Link>
}
}
export default withRouter(SafeLink);
然后您可以将 link 用作(来自 Link
的任何额外道具都可以):
<SafeLink className="some_class" to="/some_route">Link text</SafeLink>
全部 React Router NavLink 的优点与禁用 能力。
import React from "react"; // v16.3.2
import { withRouter, NavLink } from "react-router-dom"; // v4.2.2
export const Link = withRouter(function Link(props) {
const { children, history, to, staticContext, ...rest } = props;
return <>
{history.location.pathname === to ?
<span>{children}</span>
:
<NavLink {...{to, ...rest}}>{children}</NavLink>
}
</>
});
您可以使用 CSS 的 pointer-events
属性。这适用于大多数浏览器。例如你的 JS 代码:
class Foo extends React.Component {
render() {
return (
<Link to='/bar' className='disabled-link'>Bar</Link>
);
}
}
和CSS:
.disabled-link {
pointer-events: none;
}
Links:
- pointer-events CSS property
- How to disable HTML links
所附的 How to disable HTML links 答案建议同时使用 disabled
和 pointer-events: none
以获得最大的浏览器支持。
a[disabled] {
pointer-events: none;
}
Link 来源:How to disable Link
这对我有用:
<Link to={isActive ? '/link-to-route' : '#'} />
React Router 的 Route
组件有 three different ways 根据当前路由渲染内容。虽然 component
最常用于仅在比赛期间显示组件,但 children
组件采用 ({match}) => {return <stuff/>}
回调,即使在 路线不匹配.
我创建了一个 NavLink class,它将 Link 替换为跨度,并在其 to
路线处于活动状态时添加了 class .
class NavLink extends Component {
render() {
var { className, activeClassName, to, exact, ...rest } = this.props;
return(
<Route
path={to}
exact={exact}
children={({ match }) => {
if (match) {
return <span className={className + " " + activeClassName}>{this.props.children}</span>;
} else {
return <Link className={className} to={to} {...rest}/>;
}
}}
/>
);
}
}
然后像这样创建一个导航link
<NavLink to="/dashboard" className="navlink" activeClassName="active">
React Router's NavLink 做了类似的事情,但仍然允许用户点击 link 并推送历史记录。
基于 nbeuchat 的回答和组件 - 我创建了一个自己的组件改进版本,它覆盖了我项目的 react router's
Link
组件。
在我的例子中,我必须允许将一个对象传递给 to
prop(就像本机 react-router-dom
link 所做的那样),我还添加了 [=15= 的检查] 和 hash
以及 pathname
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Link as ReactLink } from 'react-router-dom';
import { withRouter } from "react-router";
const propTypes = {
to: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.object]),
location: PropTypes.object,
children: PropTypes.node,
onClick: PropTypes.func,
disabled: PropTypes.bool,
staticContext: PropTypes.object
};
class Link extends Component {
handleClick = (event) => {
if (this.props.disabled) {
event.preventDefault();
}
if (typeof this.props.to === 'object') {
let {
pathname,
search = '',
hash = ''
} = this.props.to;
let { location } = this.props;
// Prepend with ? to match props.location.search
if (search[0] !== '?') {
search = '?' + search;
}
if (
pathname === location.pathname
&& search === location.search
&& hash === location.hash
) {
event.preventDefault();
}
} else {
let { to, location } = this.props;
if (to === location.pathname + location.search + location.hash) {
event.preventDefault();
}
}
// Ensure that if we passed another onClick method as props, it will be called too
if (this.props.onClick) {
this.props.onClick(event);
}
};
render() {
let { onClick, children, staticContext, ...restProps } = this.props;
return (
<ReactLink
onClick={ this.handleClick }
{ ...restProps }
>
{ children }
</ReactLink>
);
}
}
Link.propTypes = propTypes;
export default withRouter(Link);
如果适合您的设计,请在上面放一个 div,然后操纵 z-index。
解决此问题的另一种选择是使用 ConditionalWrapper
组件,该组件根据条件呈现 <Link>
标签。
这是我根据这篇博客在这里使用的 ConditionalWrapper
组件
https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2:
const ConditionalWrapper = ({ condition, wrapper, children }) =>
condition ? wrapper(children) : children;
export default ConditionalWrapper
我们是这样使用它的:
const SearchButton = () => {
const {
searchData,
} = useContext(SearchContext)
const isValid = () => searchData?.search.length > 2
return (<ConditionalWrapper condition={isValid()}
wrapper={children => <Link href={buildUrl(searchData)}>{children}</Link>}>
<a
className={`ml-auto bg-${isValid()
? 'primary'
: 'secondary'} text-white font-filosofia italic text-lg md:text-2xl px-4 md:px-8 pb-1.5`}>{t(
'search')}</a>
</ConditionalWrapper>
)
}
此解决方案不呈现 Link
元素,并且还避免了代码重复。
如果 URL 已经激活,我如何在 react-router 中禁用 <Link>
?例如。如果我的 URL 在点击 <Link>
时不会改变,我想完全阻止点击或呈现 <span>
而不是 <Link>
。
我想到的唯一解决方案是使用 activeClassName
(或 activeStyle
)并设置 pointer-events: none;
,但我更愿意使用适用于 IE9 的解决方案和 IE10.
我不会问您为什么想要这种行为,但我想您可以将 <Link />
包装在您自己的自定义 link 组件中。
<MyLink to="/foo/bar" linktext="Maybe a link maybe a span" route={this.props.route} />
class MyLink extends Component {
render () {
if(this.props.route === this.props.to){
return <span>{this.props.linktext}</span>
}
return <Link to={this.props.to}>{this.props.linktext}</Link>
}
}
(ES6,但你大概明白了大概意思……)
另一种可能性是,如果已在同一路径上单击,则禁用单击事件。这是 与 react-router v4 一起工作的解决方案。
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
class SafeLink extends Component {
onClick(event){
if(this.props.to === this.props.history.location.pathname){
event.preventDefault();
}
// Ensure that if we passed another onClick method as props, it will be called too
if(this.props.onClick){
this.props.onClick();
}
}
render() {
const { children, onClick, ...other } = this.props;
return <Link onClick={this.onClick.bind(this)} {...other}>{children}</Link>
}
}
export default withRouter(SafeLink);
然后您可以将 link 用作(来自 Link
的任何额外道具都可以):
<SafeLink className="some_class" to="/some_route">Link text</SafeLink>
全部 React Router NavLink 的优点与禁用 能力。
import React from "react"; // v16.3.2
import { withRouter, NavLink } from "react-router-dom"; // v4.2.2
export const Link = withRouter(function Link(props) {
const { children, history, to, staticContext, ...rest } = props;
return <>
{history.location.pathname === to ?
<span>{children}</span>
:
<NavLink {...{to, ...rest}}>{children}</NavLink>
}
</>
});
您可以使用 CSS 的 pointer-events
属性。这适用于大多数浏览器。例如你的 JS 代码:
class Foo extends React.Component {
render() {
return (
<Link to='/bar' className='disabled-link'>Bar</Link>
);
}
}
和CSS:
.disabled-link {
pointer-events: none;
}
Links:
- pointer-events CSS property
- How to disable HTML links
所附的 How to disable HTML links 答案建议同时使用 disabled
和 pointer-events: none
以获得最大的浏览器支持。
a[disabled] {
pointer-events: none;
}
Link 来源:How to disable Link
这对我有用:
<Link to={isActive ? '/link-to-route' : '#'} />
React Router 的 Route
组件有 three different ways 根据当前路由渲染内容。虽然 component
最常用于仅在比赛期间显示组件,但 children
组件采用 ({match}) => {return <stuff/>}
回调,即使在 路线不匹配.
我创建了一个 NavLink class,它将 Link 替换为跨度,并在其 to
路线处于活动状态时添加了 class .
class NavLink extends Component {
render() {
var { className, activeClassName, to, exact, ...rest } = this.props;
return(
<Route
path={to}
exact={exact}
children={({ match }) => {
if (match) {
return <span className={className + " " + activeClassName}>{this.props.children}</span>;
} else {
return <Link className={className} to={to} {...rest}/>;
}
}}
/>
);
}
}
然后像这样创建一个导航link
<NavLink to="/dashboard" className="navlink" activeClassName="active">
React Router's NavLink 做了类似的事情,但仍然允许用户点击 link 并推送历史记录。
基于 nbeuchat 的回答和组件 - 我创建了一个自己的组件改进版本,它覆盖了我项目的 react router's
Link
组件。
在我的例子中,我必须允许将一个对象传递给 to
prop(就像本机 react-router-dom
link 所做的那样),我还添加了 [=15= 的检查] 和 hash
以及 pathname
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Link as ReactLink } from 'react-router-dom';
import { withRouter } from "react-router";
const propTypes = {
to: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.object]),
location: PropTypes.object,
children: PropTypes.node,
onClick: PropTypes.func,
disabled: PropTypes.bool,
staticContext: PropTypes.object
};
class Link extends Component {
handleClick = (event) => {
if (this.props.disabled) {
event.preventDefault();
}
if (typeof this.props.to === 'object') {
let {
pathname,
search = '',
hash = ''
} = this.props.to;
let { location } = this.props;
// Prepend with ? to match props.location.search
if (search[0] !== '?') {
search = '?' + search;
}
if (
pathname === location.pathname
&& search === location.search
&& hash === location.hash
) {
event.preventDefault();
}
} else {
let { to, location } = this.props;
if (to === location.pathname + location.search + location.hash) {
event.preventDefault();
}
}
// Ensure that if we passed another onClick method as props, it will be called too
if (this.props.onClick) {
this.props.onClick(event);
}
};
render() {
let { onClick, children, staticContext, ...restProps } = this.props;
return (
<ReactLink
onClick={ this.handleClick }
{ ...restProps }
>
{ children }
</ReactLink>
);
}
}
Link.propTypes = propTypes;
export default withRouter(Link);
如果适合您的设计,请在上面放一个 div,然后操纵 z-index。
解决此问题的另一种选择是使用 ConditionalWrapper
组件,该组件根据条件呈现 <Link>
标签。
这是我根据这篇博客在这里使用的 ConditionalWrapper
组件
https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2:
const ConditionalWrapper = ({ condition, wrapper, children }) =>
condition ? wrapper(children) : children;
export default ConditionalWrapper
我们是这样使用它的:
const SearchButton = () => {
const {
searchData,
} = useContext(SearchContext)
const isValid = () => searchData?.search.length > 2
return (<ConditionalWrapper condition={isValid()}
wrapper={children => <Link href={buildUrl(searchData)}>{children}</Link>}>
<a
className={`ml-auto bg-${isValid()
? 'primary'
: 'secondary'} text-white font-filosofia italic text-lg md:text-2xl px-4 md:px-8 pb-1.5`}>{t(
'search')}</a>
</ConditionalWrapper>
)
}
此解决方案不呈现 Link
元素,并且还避免了代码重复。