Javascript React路由器v4面包屑

Javascript React路由器v4面包屑,javascript,reactjs,breadcrumbs,react-router-v4,Javascript,Reactjs,Breadcrumbs,React Router V4,我正在努力实施 以下是我的路线: const routes = { '/': 'Home', '/page1': 'Page 1', '/page2': 'Page 2' }; 我可以在我的应用程序中使用此库放置面包屑,但我有以下问题: Que#1: 当我在我的面包屑中点击Home时,我可以看到URL变为http://localhost:8080然而,浏览器仍然显示我所在的页面 Que#2: 当我从第1页导航到第2页时,url从http://

我正在努力实施

以下是我的路线:

    const routes = {
      '/': 'Home',
      '/page1': 'Page 1',
      '/page2': 'Page 2'
    };
我可以在我的应用程序中使用此库放置面包屑,但我有以下问题:

Que#1:

当我在我的面包屑中点击
Home
时,我可以看到URL变为
http://localhost:8080
然而,浏览器仍然显示我所在的页面

Que#2:

当我从第1页导航到第2页时,
url
http://localhost:8080/page1
http://localhost:8080/page2

因此,面包屑显示更改为
Home/Page 2
,而不是像
Home/Page 1/Page 2

我知道这可能是因为
url
在主机名之后有
/page2
。但是,我可以实现如下显示:
主页/Page 1/Page 2

下面是我的main
App.jsx
中的代码:

<Router>
  <div>
    <Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
    <Route exact path="/" component={LandingPage}/>
    <Route path="/page1" component={Page1}/>
    <Route path="/page2" component={Page2}/>
  </div>
</Router>

如果我使用like-belowto来处理面包屑,那么我的第2页就会呈现在第1页下面:

    <Router>
      <div>
        <Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
        <Route exact path="/" component={LandingPage}/>
        <Route path="/page1" component={Page1}/>
        <Route path="/page1/page2" component={Page2}/>
      </div>
    </Router>

回答:

Que#1:无需将
元素包装在
应用程序的每个组件中。这可能是因为在每个组件中包含
元素会导致
路由器
元素“嵌套”(注意,我们在登录页中也有
路由器
标记);它不适用于
react路由器v4


Que#2:请参考此处正式标记的答案(由下面的palsrealm回答)

您的面包屑基于链接,并按设计工作。要显示页面,您需要设置一个
开关
,其中包含
路由
s,当路径改变时,该开关将加载相应的组件。差不多

<Switch> 
    <Route path='/' component={Home}/>
    <Route path='/page1' component={Page1}/>
    <Route path='/page2' component={Page2}/>
</Switch>

这也可以通过HOC实现,HOC允许您使用route config对象来设置面包屑。我已经将其开源,但源代码如下:

Breadcrumbs.jsx

import React from 'react';
import { NavLink } from 'react-router-dom';
import { withBreadcrumbs } from 'withBreadcrumbs';

const UserBreadcrumb = ({ match }) =>
  <span>{match.params.userId}</span>; // use match param userId to fetch/display user name

const routes = [
  { path: 'users', breadcrumb: 'Users' },
  { path: 'users/:userId', breadcrumb: UserBreadcrumb},
  { path: 'something-else', breadcrumb: ':)' },
];

const Breadcrumbs = ({ breadcrumbs }) => (
  <div>
    {breadcrumbs.map(({ breadcrumb, path, match }) => (
      <span key={path}>
        <NavLink to={match.url}>
          {breadcrumb}
        </NavLink>
        <span>/</span>
      </span>
    ))}
  </div>
);

export default withBreadcrumbs(routes)(Breadcrumbs);

以下组件应该在任何深度返回面包屑,主页上除外(出于明显的原因)。你不需要面包屑。我的第一次公开贡献,所以如果我遗漏了一个重要部分,如果有人能指出这一点,那就太好了。我添加了
»用于碎屑分割,但显然可以根据需要进行更新

import React from 'react'
import ReactDOM from 'react-dom'
import { Route, Link } from 'react-router-dom'
// styles
require('./styles/_breadcrumbs.scss')

// replace underscores with spaces in path names
const formatLeafName = leaf => leaf.replace('_', ' ')

// create a path based on the leaf position in the branch
const formatPath = (branch, index) => branch.slice(0, index + 1).join('/')

// output the individual breadcrumb links
const BreadCrumb = props => {
  const { leaf, index, branch } = props,
    leafPath = formatPath(branch, index),
    leafName = index == 0 ? 'home' : formatLeafName(leaf),
    leafItem =
      index + 1 < branch.length 
        ? <li className="breadcrumbs__crumb">
          <Link to={leafPath}>{leafName}</Link>
          <span className="separator">&raquo;</span>
        </li>
        : <li className="breadcrumbs__crumb">{leafName}</li>
  // the slug doesn't need a link or a separator, so we output just the leaf name

  return leafItem
}

const BreadCrumbList = props => {
  const path = props.match.url,
    listItems =
      // make sure we're not home (home return '/' on url)
      path.length > 1
      && path
        // create an array of leaf names
        .split('/')
        // send our new array to BreadCrumb for formating
        .map((leaf, index, branch) => 
          <BreadCrumb leaf={leaf} index={index} branch={branch} key={index} />
        )

  // listItem will exist anywhere but home
  return listItems && <ul className="breadcrumbs">{listItems}</ul>
}

const BreadCrumbs = props => 
  <Route path="/*" render={({ match }) => <BreadCrumbList match={match} />} />


export default BreadCrumbs
从“React”导入React
从“react dom”导入react dom
从“react router dom”导入{Route,Link}
//风格
需要('./样式/_breadcrumbs.scss'))
//将路径名中的下划线替换为空格
const formatLeafName=leaf=>leaf.replace(“”,“”)
//基于分支中的叶位置创建路径
const formatPath=(branch,index)=>branch.slice(0,index+1).join(“/”)
//输出各个面包屑链接
常量面包屑=道具=>{
const{leaf,index,branch}=props,
叶路径=格式化路径(分支、索引),
leafName=索引==0?“主”:formatLeafName(叶),
叶项=
索引+1<分支长度
?
  • {leafName} &拉阔;
  • {leafName}
  • //slug不需要链接或分隔符,因此我们只输出叶名称 退货项目 } 常量面包屑列表=道具=>{ const path=props.match.url, 列表项= //确保我们不在家(url上的主页返回“/”) 路径长度>1 &&路径 //创建一个叶名称数组 .split(“/”) //将新数组发送到BreadCrumb进行格式化 .map((叶、索引、分支)=> ) //listItem将存在于除home之外的任何位置 返回listItems&&
      {listItems}
    } 常量面包屑=道具=> } /> 导出默认面包屑
    有任何反应代码吗?这与前面给出的URL相同,谢谢。我不认为这是你能从盒子里拿出来的东西。你必须自己实现逻辑;可能是通过存储上次访问的url,并使用Link或NavLink组件手动将其添加到面包屑中。@palsrealm是正确的。您需要一个
    开关
    。另外,如果您想同时捕获“/page1”和“/page1/page2”,您需要“/page1”的路由上的
    exact
    。用您想要使用的
    路由器的代码更新我的答案。正如@Luke M WillisThanks所指定的那样,现在通过使用“精确”,两个页面在一个屏幕上呈现的问题得到了解决。但是,当我单击面包屑时,只会更改浏览器URL,而不会更改内容。有什么线索吗?当浏览器url按预期更改时,这意味着您的链接工作正常。当内容没有呈现时,这意味着应该在该url呈现的组件没有呈现,您需要检查组件和路由。
    
    import React from 'react';
    import { matchPath, withRouter } from 'react-router';
    
    const renderer = ({ breadcrumb, match }) => {
      if (typeof breadcrumb === 'function') { return breadcrumb({ match }); }
      return breadcrumb;
    };
    
    export const getBreadcrumbs = ({ routes, pathname }) => {
      const matches = [];
    
      pathname
        .replace(/\/$/, '')
        .split('/')
        .reduce((previous, current) => {
          const pathSection = `${previous}/${current}`;
    
          let breadcrumbMatch;
    
          routes.some(({ breadcrumb, path }) => {
            const match = matchPath(pathSection, { exact: true, path });
    
            if (match) {
              breadcrumbMatch = {
                breadcrumb: renderer({ breadcrumb, match }),
                path,
                match,
              };
              return true;
            }
    
            return false;
          });
    
          if (breadcrumbMatch) {
            matches.push(breadcrumbMatch);
          }
    
          return pathSection;
        });
    
      return matches;
    };
    
    export const withBreadcrumbs = routes => Component => withRouter(props => (
      <Component
        {...props}
        breadcrumbs={
          getBreadcrumbs({
            pathname: props.location.pathname,
            routes,
          })
        }
      />
    ));
    
    import React from 'react'
    import ReactDOM from 'react-dom'
    import { Route, Link } from 'react-router-dom'
    // styles
    require('./styles/_breadcrumbs.scss')
    
    // replace underscores with spaces in path names
    const formatLeafName = leaf => leaf.replace('_', ' ')
    
    // create a path based on the leaf position in the branch
    const formatPath = (branch, index) => branch.slice(0, index + 1).join('/')
    
    // output the individual breadcrumb links
    const BreadCrumb = props => {
      const { leaf, index, branch } = props,
        leafPath = formatPath(branch, index),
        leafName = index == 0 ? 'home' : formatLeafName(leaf),
        leafItem =
          index + 1 < branch.length 
            ? <li className="breadcrumbs__crumb">
              <Link to={leafPath}>{leafName}</Link>
              <span className="separator">&raquo;</span>
            </li>
            : <li className="breadcrumbs__crumb">{leafName}</li>
      // the slug doesn't need a link or a separator, so we output just the leaf name
    
      return leafItem
    }
    
    const BreadCrumbList = props => {
      const path = props.match.url,
        listItems =
          // make sure we're not home (home return '/' on url)
          path.length > 1
          && path
            // create an array of leaf names
            .split('/')
            // send our new array to BreadCrumb for formating
            .map((leaf, index, branch) => 
              <BreadCrumb leaf={leaf} index={index} branch={branch} key={index} />
            )
    
      // listItem will exist anywhere but home
      return listItems && <ul className="breadcrumbs">{listItems}</ul>
    }
    
    const BreadCrumbs = props => 
      <Route path="/*" render={({ match }) => <BreadCrumbList match={match} />} />
    
    
    export default BreadCrumbs