Material-ui 从 react-router 添加 Link 组件
Material-ui adding Link component from react-router
我正在努力将 <Link/>
组件添加到我的 material-ui AppBar
这是我的导航class:
class Navigation extends Component {
constructor(props) {
super(props)
}
render() {
var styles = {
appBar: {
flexWrap: 'wrap'
},
tabs: {
width: '100%'
}
}
return (
<AppBar showMenuIconButton={false} style={styles.appBar}>
<Tabs style={styles.tabs}>
<Tab label='Most popular ideas'/>
<Tab label='Latest ideas' />
<Tab label='My ideas' />
</Tabs>
</AppBar>
)
}
}
看起来不错:
标签是可点击的,有 fluid 动画,这很酷。但是我如何将它们与 react-router
及其“<Link/>
组件连接起来?
我试过像这样添加 onChange
监听器:
<Tab
label='My ideas'
onChange={<Link to='/myPath'></Link>}
/>
但是我收到以下错误:
Uncaught Invariant Violation: Expected onChange listener to be a function, instead got type object
如果我尝试将 <Tab/>
组件包装到 <Link/>
组件中,我会收到 <Tabs/>
组件仅接受 <Tab/>
组件的错误。
这也不起作用(没有产生错误,但点击 Tab 并没有将我带到路径):
<Tab label='Most popular ideas'>
<Link to='/popular'/>
</Tab>
如何让 <Link/>
组件与 <Tabs>
和 <AppBar>
一起工作?如果那不可能,我可以使用 material-ui
库中的任何其他组件来形成适当的菜单。
所以我的解决方案非常可靠,尽管它可能比您想要的解决方案更手动。
我一直使用的策略是实际上什至不使用 Link 组件。相反,您将使用 Tabs onChange 属性 作为可以响应 Tab 点击的回调,并使用 Parent 上的 Props 手动跟踪位置。
您可以从 react-router 导入一个名为 History 的实用程序,它将允许您手动推送位置。在使用 React-Router 时,您的组件树将可以访问 Location 道具,该道具的路径名键包含您当前位置的字符串。
我们将手动将此字符串解析为构成您当前 URL 的组件,然后使用 Switch 语句来决定当前选择了哪个选项卡以及 link 到何时标签被点击。 (这使您可以对导航进行相当程度的控制)
(例如 ['', 'latest'])
这是集成此解决方案后您的组件的外观模型。
import React from 'react';
import {History} from 'react-router';
function parseLocation(location) {
if (String(location)) {
var locationArray = location.split('/');
return locationArray;
} else {
return false;
}
};
function filterPath(path) {
let locationArray = parseLocation(path);
return locationArray[locationArray.length - 1];
};
var Navigation = React.createClass({
mixins: [History],
getPage() {
if (this.props.location.pathname) {
let pathname = this.props.location.pathname;
let pageName = filterPath(pathname);
return pageName;
} else {
return false;
}
},
decideContent() {
let page = this.getPage();
let content;
switch(page) {
case 'popular':
content = 0;
case 'latest':
content = 1;
case 'myideas':
content = 2;
default:
content = 0;
}
return content;
},
handleTabChange(value) {
let location = false;
switch (value) {
case 0:
location = 'popular';
break;
case 1:
location = 'latest';
break;
case 2:
location = 'myideas';
break;
}
if (location && location !== this.getPage()) {
this.history.pushState(null, '/'+location);
}
},
render() {
var styles = {
appBar: {
flexWrap: 'wrap'
},
tabs: {
width: '100%'
}
};
let content = this.decideContent();
let tabs = <Tabs
onChange={this.handleTabChange}
value={content}
>
<Tab label="Most Popular Ideas" value={0} />
<Tab label="Latest Ideas" value={1} />
<Tab label="My Ideas" value={2} />
</Tabs>;
return (
<AppBar showMenuIconButton={false} style={styles.appBar}>
{tabs}
</AppBar>
);
}
});
您现在可以这样做:
<Tabs onChange={this.changeTab} value={value}>
<Tab value={0} label="first" containerElement={<Link to="/first"/>} />
<Tab value={1} label="second" containerElement={<Link to="/second"/>}/>
<Tab value={2} label="third" containerElement={<Link to="/third"/>} />
</Tabs>
对于 Material UI 1.0 with Typescript:请参阅下面@oglas 的 。
对于 Material-UI 1.0 和纯 JS:
<Tabs value={value} onChange={this.handleChange}>
{
this.props.tabs.map(
({label, path})=><Tab key={label}
label={label}
className={classes.tabLink}
component={Link}
to={path} />
)
}
</Tabs>
而classes.tabLink
定义为:
tabLink : {
display:"flex",
alignItems:"center",
justifyContent:"center"
}
这是如何运作的?
所有继承自 ButtonBase
的 mui 1.0 组件都支持 component
属性,请参阅 ButtonBase。这个想法是允许您控制组件呈现为它的 wrapper/root 元素的内容。 Tab
也有这个特性,虽然在写这个答案的时候这个 prop 没有被记录 明确地 ,但是因为 Tab
继承自 ButtonBase
,所有它的道具继续存在(文档确实涵盖了这一点)。
ButtonBase
的另一个特点是所有未被 ButtonBase
或继承的组件使用的额外属性分布在指定的 component
上。我们已经使用此行为将 Link
使用的 to
道具交给 Tab
控制。你可以用同样的方式发送任何额外的道具。请注意,ButtonBase
和 Tab
.
都明确记录了这一点
感谢@josh-l 要求添加此内容。
由于我们使用的是 TypeScript,所以我无法使用@hazardous 解决方案。这就是我们为 material-ui v1.0.0-beta.16
和 react-router 4.2.0
实现路由的方式。我们拆分 this.props.history.location.pathname
的原因是因为我们需要访问 /renewals/123
例如。如果我们不这样做,我们会收到以下警告,并且不会显示任何选项卡:Warning: Material-UI: the value provided '/renewals/123' is invalid
带导入的完整代码:
import * as React from "react";
import * as ReactDOM from "react-dom";
import * as ReactRouter from "react-router";
import * as PropTypes from "prop-types";
import { Switch, Route, Redirect, Link } from "react-router-dom";
import { Cases } from './../Cases';
import { SidePane } from './../SidePane';
import { withStyles, WithStyles } from 'material-ui/styles';
import Paper from 'material-ui/Paper';
import Tabs, { Tab } from 'material-ui/Tabs';
import { withRouter } from "react-router-dom";
import Badge from 'material-ui/Badge';
import Grid from 'material-ui/Grid';
import { Theme } from 'material-ui/styles';
import SimpleLineIcons from '../../Shared/SimpleLineIcons'
interface IState {
userName: string;
}
interface IProps {
history?: any
}
const styles = (theme: Theme) => ({
root: theme.typography.display1,
badge: {
right: '-28px',
color: theme.palette.common.white,
},
imageStyle:{
float: 'left',
height: '40px',
paddingTop: '10px'
},
myAccount: {
float: 'right'
},
topMenuAccount: {
marginLeft: '0.5em',
cursor: 'pointer'
}
});
type WithStyleProps = 'root' | 'badge' | 'imageStyle' | 'myAccount' | 'topMenuAccount';
class Menu extends React.Component<IProps & WithStyles<WithStyleProps>, IState> {
constructor(props: IProps & WithStyles<WithStyleProps>) {
super(props);
this.state = {
userName: localStorage.userName ? 'userName ' + localStorage.userName : ""
}
}
componentDidMount() {
this.setState({ userName: localStorage.userName ? localStorage.userName : "" })
}
logout(event: any) {
localStorage.removeItem('token');
window.location.href = "/"
}
handleChange = (event: any, value: any) => {
this.props.history.push(value);
};
render() {
const classes = this.props.classes;
let route = '/' + this.props.history.location.pathname.split('/')[1];
return (
<div>
<Grid container spacing={24}>
<Grid item xs={12} className={classes.root}>
<img src="/Features/Client/Menu/logo.png" alt="Logo" className={classes.imageStyle} />
<div className={this.props.classes.myAccount}>
<span><span className={this.props.classes.topMenuAccount}>MY ACCOUNT</span><span className={classes.topMenuAccount}><SimpleLineIcons iconName={'user'} />▾</span></span>
<span onClick={this.logout} className={classes.topMenuAccount}><SimpleLineIcons iconName={'logout'} /></span>
</div>
</Grid>
<Grid item xs={12} >
<div className="route-list">
<Tabs
value={route}
onChange={this.handleChange}
indicatorColor="primary"
textColor="primary"
>
<Tab label="Overview" value="/" />
<Tab label={<Badge classes={{ badge: classes.badge }} badgeContent={this.props.caseRenewalCount} color="primary">
Renewals
</Badge>} value="/renewals" />
</Tabs>
</div>
</Grid>
</Grid>
</div>
);
}
}
export default withStyles(styles)(withRouter(Menu))
你可以试试这个简单的方法
<Tab label='Most popular ideas' to='/myPath' component={Link} />
路由器驱动选项卡的 TypeScript 实现。
对于那些寻找 TypeScript 实现的人。易于配置。由 tabs
配置驱动。
interface ITabsPageProps {
match: match<{page: string}>;
history: History;
}
const tabs = [{
label: 'Fist Tab',
link: 'fist-tab',
component: <FirstTabContent/>
}, {
label: 'Second Tab',
link: 'second-tab',
component: <SecondTabContent/>
}, {
label: 'Third Tab',
link: 'third-tab',
component: <ThirdTabContent/>
}];
export class TabsPage extends React.Component<ITabsPageProps> {
handleChange(tabLink: string) {
this.props.history.push(`/tabs-page/${tabLink}`);
}
render() {
const currentTab = this.props.match.params.page;
const selectedTab = tabs.find(tab => currentTab === tab.link);
return (
<Fragment>
<Tabs
value={currentTab}
onChange={(event, value) => this.handleChange(value)}
>
{tabs.map(tab => (
<Tab
key={tab.link}
value={tab.link}
label={tab.label}
/>
))}
</Tabs>
{selectedTab && selectedTab.component}
</Fragment>
);
}
}
这可以使用 material-ui 中的 <Link />
而不是直接使用 react-router 中的 <Link />
或 <NavLink />
来解决。可以在此处的文档中找到相同的示例。
https://material-ui.com/components/links/
另外 <Button />
标签有一个组件属性来实现这个
<Button color="inherit" component={Link} to={"/logout"}>Logout</Button>
可以在此处找到关于此的广泛讨论
检查此 link,我实施了解决方案并为我工作
这是 React 的另一个实现,它带有钩子,Material-UI 带有选项卡,React Router 带有 Link,还有 TypeScript。
import * as React from "react";
import { BrowserRouter as Router, Route, Redirect, Switch, Link, LinkProps } from 'react-router-dom';
import AppBar from '@material-ui/core/AppBar';
import Tabs from '@material-ui/core/Tabs';
import { default as Tab, TabProps } from '@material-ui/core/Tab';
import Home from './Home';
import ProductManagement from './ProductManagement';
import Development from './Development';
import HomeIcon from '@material-ui/icons/Home';
import CodeIcon from '@material-ui/icons/Code';
import TimelineIcon from '@material-ui/icons/Timeline';
const LinkTab: React.ComponentType<TabProps & LinkProps> = Tab as React.ComponentType<TabProps & LinkProps>;
function NavBar() {
const [value, setValue] = React.useState(0);
const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
setValue(newValue);
};
return (
<div >
<AppBar position="static" >
<Tabs value={value} onChange={handleChange} centered>
<LinkTab label='Home' icon={ <HomeIcon />} component={Link} to="/" />
<LinkTab label='Development' icon={<CodeIcon />} component={Link} to="/dev" />
<LinkTab label='Product Management' icon={<TimelineIcon />} component={Link} to="/pm" />
</Tabs>
</AppBar>
</div>
)
};
export default function App() {
return (
<Router>
<div>
<NavBar />
<Switch>
<Route exact path="/" component={ Home } />
<Route exact path="/dev" component={ Development } />
<Route exact path="/pm" component={ ProductManagement } />
<Redirect from="/" to="/" />
</Switch>
</div>
</Router>
)
}
对于希望将 Material-ui Link 换成 Next.js Link
的任何人
import Link from "next/link"
import MuiLink from "@material-ui/core/Link"
const CustomNextLink = ({href, alt}) => ({children, ...rest}) => (
<Link href={href} alt={alt}>
<MuiLink {...rest}>
{children}
</MuiLink>
</Link>)
然后传给你Tab组件
<Tab
key={...}
label={title}
icon={icon}
component={CustomNextLink({href: to, alt: title})}
style={...}
className={...}
classes={{selected: ...}}
{...a11yProps(index)}
/>
如果你使用 NextJs,你可以那样做,并创建你自己的组件。
*我没有用 'a' 标签包裹标签,因为它自动添加了
const WrapTab = (props) => {
const { href } = props
return (
<Link href={href} style={{ width: "100%" }}>
<Tab {...props} />
</Link>
)}
然后这是你的 return
<Tabs
value={value}
indicatorColor="primary"
textColor="primary"
onChange={handleChange}
variant="fullWidth"
>
<WrapTab href="/testPage/?tab=0" icon={<MenuIcon />} />
<WrapTab href="/testPage/?tab=1" icon={<StampIcon2 />} />
<WrapTab href="/testPage/?tab=2" icon={<ShopIcon />} />
<WrapTab href="/testPage/?tab=3" icon={<PenIcon />} />
<WrapTab href="/testPage/?tab=4" icon={<ProfileIcon />} />
</Tabs>
link 到 material-ui 文档:
https://material-ui.com/guides/composition/
使用 href=""
选项,如下所示:
<Tab
href="/en/getting-started"
label="Contact US"
style={{ color: "white", textDecoration: "none" }}
/>
要消除点击时的连锁反应,请使用选项 disableRipple
这似乎对我有用
import { Link as RouterLink } from 'react-router-dom';
import Link from '@mui/material/Link';
<Link to={menuItem.url} component={RouterLink} aria-current="page">
{menuItem.label}
</Link>
我正在努力将 <Link/>
组件添加到我的 material-ui AppBar
这是我的导航class:
class Navigation extends Component {
constructor(props) {
super(props)
}
render() {
var styles = {
appBar: {
flexWrap: 'wrap'
},
tabs: {
width: '100%'
}
}
return (
<AppBar showMenuIconButton={false} style={styles.appBar}>
<Tabs style={styles.tabs}>
<Tab label='Most popular ideas'/>
<Tab label='Latest ideas' />
<Tab label='My ideas' />
</Tabs>
</AppBar>
)
}
}
看起来不错:
标签是可点击的,有 fluid 动画,这很酷。但是我如何将它们与 react-router
及其“<Link/>
组件连接起来?
我试过像这样添加 onChange
监听器:
<Tab
label='My ideas'
onChange={<Link to='/myPath'></Link>}
/>
但是我收到以下错误:
Uncaught Invariant Violation: Expected onChange listener to be a function, instead got type object
如果我尝试将 <Tab/>
组件包装到 <Link/>
组件中,我会收到 <Tabs/>
组件仅接受 <Tab/>
组件的错误。
这也不起作用(没有产生错误,但点击 Tab 并没有将我带到路径):
<Tab label='Most popular ideas'>
<Link to='/popular'/>
</Tab>
如何让 <Link/>
组件与 <Tabs>
和 <AppBar>
一起工作?如果那不可能,我可以使用 material-ui
库中的任何其他组件来形成适当的菜单。
所以我的解决方案非常可靠,尽管它可能比您想要的解决方案更手动。
我一直使用的策略是实际上什至不使用 Link 组件。相反,您将使用 Tabs onChange 属性 作为可以响应 Tab 点击的回调,并使用 Parent 上的 Props 手动跟踪位置。
您可以从 react-router 导入一个名为 History 的实用程序,它将允许您手动推送位置。在使用 React-Router 时,您的组件树将可以访问 Location 道具,该道具的路径名键包含您当前位置的字符串。
我们将手动将此字符串解析为构成您当前 URL 的组件,然后使用 Switch 语句来决定当前选择了哪个选项卡以及 link 到何时标签被点击。 (这使您可以对导航进行相当程度的控制)
(例如 ['', 'latest'])
这是集成此解决方案后您的组件的外观模型。
import React from 'react';
import {History} from 'react-router';
function parseLocation(location) {
if (String(location)) {
var locationArray = location.split('/');
return locationArray;
} else {
return false;
}
};
function filterPath(path) {
let locationArray = parseLocation(path);
return locationArray[locationArray.length - 1];
};
var Navigation = React.createClass({
mixins: [History],
getPage() {
if (this.props.location.pathname) {
let pathname = this.props.location.pathname;
let pageName = filterPath(pathname);
return pageName;
} else {
return false;
}
},
decideContent() {
let page = this.getPage();
let content;
switch(page) {
case 'popular':
content = 0;
case 'latest':
content = 1;
case 'myideas':
content = 2;
default:
content = 0;
}
return content;
},
handleTabChange(value) {
let location = false;
switch (value) {
case 0:
location = 'popular';
break;
case 1:
location = 'latest';
break;
case 2:
location = 'myideas';
break;
}
if (location && location !== this.getPage()) {
this.history.pushState(null, '/'+location);
}
},
render() {
var styles = {
appBar: {
flexWrap: 'wrap'
},
tabs: {
width: '100%'
}
};
let content = this.decideContent();
let tabs = <Tabs
onChange={this.handleTabChange}
value={content}
>
<Tab label="Most Popular Ideas" value={0} />
<Tab label="Latest Ideas" value={1} />
<Tab label="My Ideas" value={2} />
</Tabs>;
return (
<AppBar showMenuIconButton={false} style={styles.appBar}>
{tabs}
</AppBar>
);
}
});
您现在可以这样做:
<Tabs onChange={this.changeTab} value={value}>
<Tab value={0} label="first" containerElement={<Link to="/first"/>} />
<Tab value={1} label="second" containerElement={<Link to="/second"/>}/>
<Tab value={2} label="third" containerElement={<Link to="/third"/>} />
</Tabs>
对于 Material UI 1.0 with Typescript:请参阅下面@oglas 的
对于 Material-UI 1.0 和纯 JS:
<Tabs value={value} onChange={this.handleChange}>
{
this.props.tabs.map(
({label, path})=><Tab key={label}
label={label}
className={classes.tabLink}
component={Link}
to={path} />
)
}
</Tabs>
而classes.tabLink
定义为:
tabLink : {
display:"flex",
alignItems:"center",
justifyContent:"center"
}
这是如何运作的?
所有继承自 ButtonBase
的 mui 1.0 组件都支持 component
属性,请参阅 ButtonBase。这个想法是允许您控制组件呈现为它的 wrapper/root 元素的内容。 Tab
也有这个特性,虽然在写这个答案的时候这个 prop 没有被记录 明确地 ,但是因为 Tab
继承自 ButtonBase
,所有它的道具继续存在(文档确实涵盖了这一点)。
ButtonBase
的另一个特点是所有未被 ButtonBase
或继承的组件使用的额外属性分布在指定的 component
上。我们已经使用此行为将 Link
使用的 to
道具交给 Tab
控制。你可以用同样的方式发送任何额外的道具。请注意,ButtonBase
和 Tab
.
感谢@josh-l 要求添加此内容。
由于我们使用的是 TypeScript,所以我无法使用@hazardous 解决方案。这就是我们为 material-ui v1.0.0-beta.16
和 react-router 4.2.0
实现路由的方式。我们拆分 this.props.history.location.pathname
的原因是因为我们需要访问 /renewals/123
例如。如果我们不这样做,我们会收到以下警告,并且不会显示任何选项卡:Warning: Material-UI: the value provided '/renewals/123' is invalid
带导入的完整代码:
import * as React from "react";
import * as ReactDOM from "react-dom";
import * as ReactRouter from "react-router";
import * as PropTypes from "prop-types";
import { Switch, Route, Redirect, Link } from "react-router-dom";
import { Cases } from './../Cases';
import { SidePane } from './../SidePane';
import { withStyles, WithStyles } from 'material-ui/styles';
import Paper from 'material-ui/Paper';
import Tabs, { Tab } from 'material-ui/Tabs';
import { withRouter } from "react-router-dom";
import Badge from 'material-ui/Badge';
import Grid from 'material-ui/Grid';
import { Theme } from 'material-ui/styles';
import SimpleLineIcons from '../../Shared/SimpleLineIcons'
interface IState {
userName: string;
}
interface IProps {
history?: any
}
const styles = (theme: Theme) => ({
root: theme.typography.display1,
badge: {
right: '-28px',
color: theme.palette.common.white,
},
imageStyle:{
float: 'left',
height: '40px',
paddingTop: '10px'
},
myAccount: {
float: 'right'
},
topMenuAccount: {
marginLeft: '0.5em',
cursor: 'pointer'
}
});
type WithStyleProps = 'root' | 'badge' | 'imageStyle' | 'myAccount' | 'topMenuAccount';
class Menu extends React.Component<IProps & WithStyles<WithStyleProps>, IState> {
constructor(props: IProps & WithStyles<WithStyleProps>) {
super(props);
this.state = {
userName: localStorage.userName ? 'userName ' + localStorage.userName : ""
}
}
componentDidMount() {
this.setState({ userName: localStorage.userName ? localStorage.userName : "" })
}
logout(event: any) {
localStorage.removeItem('token');
window.location.href = "/"
}
handleChange = (event: any, value: any) => {
this.props.history.push(value);
};
render() {
const classes = this.props.classes;
let route = '/' + this.props.history.location.pathname.split('/')[1];
return (
<div>
<Grid container spacing={24}>
<Grid item xs={12} className={classes.root}>
<img src="/Features/Client/Menu/logo.png" alt="Logo" className={classes.imageStyle} />
<div className={this.props.classes.myAccount}>
<span><span className={this.props.classes.topMenuAccount}>MY ACCOUNT</span><span className={classes.topMenuAccount}><SimpleLineIcons iconName={'user'} />▾</span></span>
<span onClick={this.logout} className={classes.topMenuAccount}><SimpleLineIcons iconName={'logout'} /></span>
</div>
</Grid>
<Grid item xs={12} >
<div className="route-list">
<Tabs
value={route}
onChange={this.handleChange}
indicatorColor="primary"
textColor="primary"
>
<Tab label="Overview" value="/" />
<Tab label={<Badge classes={{ badge: classes.badge }} badgeContent={this.props.caseRenewalCount} color="primary">
Renewals
</Badge>} value="/renewals" />
</Tabs>
</div>
</Grid>
</Grid>
</div>
);
}
}
export default withStyles(styles)(withRouter(Menu))
你可以试试这个简单的方法
<Tab label='Most popular ideas' to='/myPath' component={Link} />
路由器驱动选项卡的 TypeScript 实现。
对于那些寻找 TypeScript 实现的人。易于配置。由 tabs
配置驱动。
interface ITabsPageProps {
match: match<{page: string}>;
history: History;
}
const tabs = [{
label: 'Fist Tab',
link: 'fist-tab',
component: <FirstTabContent/>
}, {
label: 'Second Tab',
link: 'second-tab',
component: <SecondTabContent/>
}, {
label: 'Third Tab',
link: 'third-tab',
component: <ThirdTabContent/>
}];
export class TabsPage extends React.Component<ITabsPageProps> {
handleChange(tabLink: string) {
this.props.history.push(`/tabs-page/${tabLink}`);
}
render() {
const currentTab = this.props.match.params.page;
const selectedTab = tabs.find(tab => currentTab === tab.link);
return (
<Fragment>
<Tabs
value={currentTab}
onChange={(event, value) => this.handleChange(value)}
>
{tabs.map(tab => (
<Tab
key={tab.link}
value={tab.link}
label={tab.label}
/>
))}
</Tabs>
{selectedTab && selectedTab.component}
</Fragment>
);
}
}
这可以使用 material-ui 中的 <Link />
而不是直接使用 react-router 中的 <Link />
或 <NavLink />
来解决。可以在此处的文档中找到相同的示例。
https://material-ui.com/components/links/
另外 <Button />
标签有一个组件属性来实现这个
<Button color="inherit" component={Link} to={"/logout"}>Logout</Button>
可以在此处找到关于此的广泛讨论
检查此 link,我实施了解决方案并为我工作
这是 React 的另一个实现,它带有钩子,Material-UI 带有选项卡,React Router 带有 Link,还有 TypeScript。
import * as React from "react";
import { BrowserRouter as Router, Route, Redirect, Switch, Link, LinkProps } from 'react-router-dom';
import AppBar from '@material-ui/core/AppBar';
import Tabs from '@material-ui/core/Tabs';
import { default as Tab, TabProps } from '@material-ui/core/Tab';
import Home from './Home';
import ProductManagement from './ProductManagement';
import Development from './Development';
import HomeIcon from '@material-ui/icons/Home';
import CodeIcon from '@material-ui/icons/Code';
import TimelineIcon from '@material-ui/icons/Timeline';
const LinkTab: React.ComponentType<TabProps & LinkProps> = Tab as React.ComponentType<TabProps & LinkProps>;
function NavBar() {
const [value, setValue] = React.useState(0);
const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
setValue(newValue);
};
return (
<div >
<AppBar position="static" >
<Tabs value={value} onChange={handleChange} centered>
<LinkTab label='Home' icon={ <HomeIcon />} component={Link} to="/" />
<LinkTab label='Development' icon={<CodeIcon />} component={Link} to="/dev" />
<LinkTab label='Product Management' icon={<TimelineIcon />} component={Link} to="/pm" />
</Tabs>
</AppBar>
</div>
)
};
export default function App() {
return (
<Router>
<div>
<NavBar />
<Switch>
<Route exact path="/" component={ Home } />
<Route exact path="/dev" component={ Development } />
<Route exact path="/pm" component={ ProductManagement } />
<Redirect from="/" to="/" />
</Switch>
</div>
</Router>
)
}
对于希望将 Material-ui Link 换成 Next.js Link
的任何人import Link from "next/link"
import MuiLink from "@material-ui/core/Link"
const CustomNextLink = ({href, alt}) => ({children, ...rest}) => (
<Link href={href} alt={alt}>
<MuiLink {...rest}>
{children}
</MuiLink>
</Link>)
然后传给你Tab组件
<Tab
key={...}
label={title}
icon={icon}
component={CustomNextLink({href: to, alt: title})}
style={...}
className={...}
classes={{selected: ...}}
{...a11yProps(index)}
/>
如果你使用 NextJs,你可以那样做,并创建你自己的组件。
*我没有用 'a' 标签包裹标签,因为它自动添加了
const WrapTab = (props) => {
const { href } = props
return (
<Link href={href} style={{ width: "100%" }}>
<Tab {...props} />
</Link>
)}
然后这是你的 return
<Tabs
value={value}
indicatorColor="primary"
textColor="primary"
onChange={handleChange}
variant="fullWidth"
>
<WrapTab href="/testPage/?tab=0" icon={<MenuIcon />} />
<WrapTab href="/testPage/?tab=1" icon={<StampIcon2 />} />
<WrapTab href="/testPage/?tab=2" icon={<ShopIcon />} />
<WrapTab href="/testPage/?tab=3" icon={<PenIcon />} />
<WrapTab href="/testPage/?tab=4" icon={<ProfileIcon />} />
</Tabs>
link 到 material-ui 文档: https://material-ui.com/guides/composition/
使用 href=""
选项,如下所示:
<Tab
href="/en/getting-started"
label="Contact US"
style={{ color: "white", textDecoration: "none" }}
/>
要消除点击时的连锁反应,请使用选项 disableRipple
这似乎对我有用
import { Link as RouterLink } from 'react-router-dom';
import Link from '@mui/material/Link';
<Link to={menuItem.url} component={RouterLink} aria-current="page">
{menuItem.label}
</Link>