【问题标题】:Material-UI Breadcrumb Integration with react-routerMaterial-UI 面包屑导航与 react-router 集成
【发布时间】:2019-10-22 16:14:08
【问题描述】:

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

Material-UI 网站上有一个如何使用它的示例,但它需要使用静态面包屑名称映射。我已经尝试使用 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”,我希望面包屑的输出是:

首页 / Level1 / Level2

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

首页/第 1 级

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

【问题讨论】:

    标签: reactjs react-router material-ui


    【解决方案1】:

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

    这是一个修改版的 Material UI Breadcrumb 示例,与 react 路由器集成。

    在这里试用完整的程序 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>
    }
    

    【讨论】:

      【解决方案2】:

      我编辑了 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>
        )
      }
      

      【讨论】:

        【解决方案3】:

        我决定发布一个单独的答案,而不是对您的代码发表评论,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);
        

        【讨论】:

          猜你喜欢
          • 2020-03-23
          • 2021-02-21
          • 2019-07-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-14
          • 1970-01-01
          相关资源
          最近更新 更多