Material-UI面包屑与react-router集成

时间:2019-06-07 07:06:17

标签: reactjs react-router material-ui

我正在尝试将Material-UI面包屑与react-router一起使用。如何以编程方式检测当前路线。

在Material-UI网站上有一个有关如何使用它的示例,但是它需要使用静态的BreadcrumbNameMap。我已经尝试使用HOC“ withRouter”拆分路径名,但是它不起作用。

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import { Breadcrumbs, Link, Paper, Typography} from "@material-ui/core";

import { withRouter } from "react-router-dom";

import { useTranslation } from "../Translate";

const useStyles = makeStyles(theme => ({
    root: {
        justifyContent: "center",
        flexWrap: "wrap",
    },
    paper: {
        padding: theme.spacing(1, 2),
    },
}));

const breadcrumbNameMap = {
    "/inbox": "Inbox",
    "/inbox/important": "Important",
    "/trash": "Trash",
    "/spam": "Spam",
    "/drafts": "Drafts",
};

function SimpleBreadcrumbs(props) {
    const classes = useStyles();
    console.log("Breadcrumbs", props);
    const { location } = props;
    const pathnames = location.pathname.split("/").filter(x => x);
    console.log("pathnames", pathnames);

    return (
        <div className={classes.root}>
            <Paper elevation={0} className={classes.paper}>
                <Breadcrumbs aria-label="Breadcrumb">
                    <Link color="inherit" href="/">
                        Home
                    </Link>
                    {pathnames.map((value, index) => {
                        const last = index === pathnames.length - 1;
                        const to = `/${pathnames
                            .slice(0, index + 1)
                            .join("/")}`;

                        console.log("last", last, "to", to);

                        const path = value.split("-");
                        console.log("path", path);
                        // Convert first char of string to uppercase
                        path.forEach((item, i) => {
                            // Only capitalize starting from the second element
                            if (i > 0) {
                                path[i] =
                                    path[i].charAt(0).toUpperCase() +
                                    path[i].slice(1);
                            }
                        });

                        // return (
                        //     <Typography color="textPrimary" key={to}>
                        //         {useTranslation(path.join(""))}
                        //     </Typography>
                        // );

                        // // return (
                        // //     <Typography color="textPrimary" key={to}>
                        // //         {pathnames[to]}
                        // //     </Typography>
                        // // );

                        return last ? (
                            <Typography color="textPrimary" key={to}>
                                {breadcrumbNameMap[to]}
                            </Typography>
                        ) : (
                            <Link color="inherit" to={to} key={to}>
                                {useTranslation(path.join(""))}
                            </Link>
                        );
                    })}
                </Breadcrumbs>
            </Paper>
        </div>
    );
}

export default withRouter(SimpleBreadcrumbs);

如果浏览器中的URL指向“ http://example.com/level1/level2”,则我希望面包屑的输出为:

首页/ 1级/ 2级

如果浏览器中的URL为“ http://example.com/level1/”,我希望:

首页/ 1级

翻译也可以在以后添加。我包括它是为了显示最终的预期结果。

3 个答案:

答案 0 :(得分:1)

仅当面包屑上的标签不同时,才需要面包屑名称映射,然后链接URL(例如,路径“ / level1”在面包屑中显示为“级别1”。

这里是与React Router集成的Material UI Breadcrumb示例的修改版本。

在这里尝试完整的程序 https://codesandbox.io/s/dark-architecture-sgl12?fontsize=14

https://sgl12.codesandbox.io/level1/level2

import React from 'react';
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
import Typography from '@material-ui/core/Typography';
import { Link as RouterLink } from 'react-router-dom';
import { Route, BrowserRouter as Router } from 'react-router-dom';

function SimpleBreadcrumbs() {
  return <Route>
    {({ location }) => {
      const pathnames = location.pathname.split('/').filter(x => x);
      return (
        <Breadcrumbs aria-label="Breadcrumb">
          <RouterLink color="inherit" to="/">
            Home
            </RouterLink>
          {pathnames.map((value, index) => {
            const last = index === pathnames.length - 1;
            const to = `/${pathnames.slice(0, index + 1).join('/')}`;

            return last ? (
              <Typography color="textPrimary" key={to}>
                {value}
              </Typography>
            ) : (
                <RouterLink color="inherit" to={to} key={to}>
                  {value}
                </RouterLink>
              );
          })}
        </Breadcrumbs>
      );
    }}
  </Route>

}

export default function App() {
  return <div>
    <Router>
      <SimpleBreadcrumbs />

      <Route path='/' exact component={Home}></Route>
      <Route path='/level1' exact component={Level1}></Route>
      <Route path='/level1/level2' exact component={Level2}></Route>

    </Router>
  </div>
}

答案 1 :(得分:0)

我决定发布一个单独的答案,而不是对您的代码Meera进行注释。谢谢您的帮助。我修改了地图功能的主体部分,并添加了翻译功能。可悲的是,它对我来说无法通过react hooks功能使用,因此这就是为什么我将其转换为类组件。

我的组件现在看起来像这样:

import React, { PureComponent } from "react";
import * as PropTypes from "prop-types";
import { Breadcrumbs, Link, Paper, Typography } from "@material-ui/core";
import { connect } from "react-redux";
import { Route, Link as RouterLink } from "react-router-dom";

import { LanguageActions } from "../../redux/actions";

/**
 * This component has to be a class component to be able
 * to translate the path values dynamically.
 * React hooks are not working in this case.
 */
class SimpleBreadcrumbs extends PureComponent {
    render = () => {
        const { translate } = this.props;
        const LinkRouter = props => <Link {...props} component={RouterLink} />;

        return (
            <Paper elevation={0} style={{ padding: "8px 16px" }}>
                <Route>
                    {({ location }) => {
                        const pathnames = location.pathname
                            .split("/")
                            .filter(x => x);
                        return (
                            <Breadcrumbs aria-label="Breadcrumb">
                                <LinkRouter
                                    color="inherit"
                                    component={RouterLink}
                                    to="/"
                                >
                                    Home
                                </LinkRouter>
                                {pathnames.map((value, index) => {
                                    const last = index === pathnames.length - 1;
                                    const to = `/${pathnames
                                        .slice(0, index + 1)
                                        .join("/")}`;

                                    // Split value so the string can be transformed and parsed later.
                                    const path = value.split("-");
                                    // Convert first char of string to uppercase.
                                    path.forEach((item, i) => {
                                        // Only capitalize starting from the second element.
                                        if (i > 0) {
                                            path[i] =
                                                path[i]
                                                    .charAt(0)
                                                    .toUpperCase() +
                                                path[i].slice(1);
                                        }
                                    });

                                    return last ? (
                                        <Typography
                                            color="textPrimary"
                                            key={to}
                                        >
                                            {translate(path.join(""))}
                                        </Typography>
                                    ) : (
                                        <LinkRouter
                                            color="inherit"
                                            to={to}
                                            key={to}
                                        >
                                            {translate(path.join(""))}
                                        </LinkRouter>
                                    );
                                })}
                            </Breadcrumbs>
                        );
                    }}
                </Route>
            </Paper>
        );
    };
}

// To be able to translate every breadcrumb step,
// translations have to be passed down to this component.
// Otherwise the component does not get notified
// if user decides to switch language
const connector = connect(
    ({ translations }) => ({ translations }),
    dispatch => ({
        translate: key => dispatch(LanguageActions.translate(key)),
    })
);

SimpleBreadcrumbs.propTypes = {
    translate: PropTypes.func,
};

SimpleBreadcrumbs.defaultProps = {
    translate: () => {},
};

export default connector(SimpleBreadcrumbs);

答案 2 :(得分:0)

我已经编辑了Meera的出色代码,以解决我面临的一些问题: 我想要标题大小写的链接,而不是小写的。我添加了useLocation钩子,并进行了其他一些更改。

import React from 'react'
import { useLocation, Link as RouterLink } from 'react-router-dom'
import { Breadcrumbs, Typography, Link } from '@material-ui/core'

function toTitleCase(str) {
  return str.replace(/\b\w+/g, function (s) {
    return s.charAt(0).toUpperCase() + s.substr(1).toLowerCase()
  })
}

export default function () {
  let location = useLocation()
  const pathnames = location.pathname.split('/').filter((x) => x)

  return (
    <Breadcrumbs aria-label='Breadcrumb'>
      <Link color='inherit' component={RouterLink} to='/'>
        Home
      </Link>
      {pathnames.map((value, index) => {
        const last = index === pathnames.length - 1
        const to = `/${pathnames.slice(0, index + 1).join('/')}`

        return last ? (
          <Typography color='textPrimary' key={to}>
            {toTitleCase(value)}
          </Typography>
        ) : (
          <Link color='inherit' component={RouterLink} to='/' key={to}>
            {toTitleCase(value)}
          </Link>
        )
      })}
    </Breadcrumbs>
  )
}