用React刻自己的投资Dashboard Day18 - 选单列active style功能

tags: 2021铁人赛 React

上一篇将选单列做出来,并且完成点击上方按钮会跳转至对应页面的功能,不过总觉得好像少了些什麽?原来是点击按钮之後,按钮的样式没有跟着改变,会让使用者不知道目前到底是在哪一个页面,而所谓跟着点击动作改变按钮样式的功能就称为active。

说起来这个功能是非常简单的,不过也是弄了蛮久,因为架构上的不熟悉以及使用react-bootstrap套件,要动态调整按钮的active样式变得有点困难,研究了技术文件许久才知道怎麽写,下面就把这个过程记录下来。

期望达成的效果

React-Bootstrap内建activeKey功能

看了一下react-bootstrap官方文件,发现Nav这个component有内建activeKey功能:

Name Type Description
activeKey string / number Marks the NavItem with a matching eventKey (or href if present) as active.

也就是说,可以使用eventKey或是href去替NavItem加上active class。使用方式如下:

目前activeKey指到/home这个路径,那home这个NavItem就会多一个active class,所以只要可以随着所在的路径动态改变activeKey,就可以更动active class的位置。

<Nav
  activeKey="/home"
>
  <Nav.Item>
    <Nav.Link href="/home">Active</Nav.Link>
  </Nav.Item>
  <Nav.Item>
    <Nav.Link eventKey="link-1">Link</Nav.Link>
  </Nav.Item>
  <Nav.Item>
    <Nav.Link eventKey="link-2">Link</Nav.Link>
  </Nav.Item>
  <Nav.Item>
    <Nav.Link eventKey="disabled" disabled>
      Disabled
    </Nav.Link>
  </Nav.Item>
</Nav>

传递路径至Navbar

那要怎麽动态改变activeKey呢?只要透过props将路径传递给Navbar这个元件即可。因为这次传递路径的架构稍微复杂了一些,所以透过props传递好几层才到Navbar。

过程由上而下大概是这样:

  • 从App.js导入路由层RouteLayer
    src/App.js
import React from 'react';
import './App.css';
import RouterLayer from "./routerLayer";

function App() {
  return (
    <div className="App">
      <RouterLayer />
    </div>
  );
}

export default App;

  • 路由层将路径资料传递给Layout
    src/routerLayer/index.js
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import routes from "../App-route";
import Layout from "../layout";

const RouterLayer = () => {
  return (
    <Router>
      <Switch>
        {routes &&
          routes
            .filter((r) => r.public)
            .map((route) => (
              <Route exact key={route.key} path={route.path}>
                <Layout {...route} />
              </Route>
            ))}
      </Switch>
    </Router>
  );
};

export default RouterLayer;
  • Layout将路径资料传递给Header
    src/layout/index.js
import React from "react";
import Header from "./header";
import Body from "./body";

const Layout = (props) => {
  return (
    <React.Fragment>
      <Header {...props} />
      <Body {...props} />
    </React.Fragment>
  );
};

export default Layout;
  • Header将路径资料传递给Navbar
    src/layout/index.js
import React from "react";
import Navbar from "../../components/Navbar/Navbar";

const Header = (props) => {
  return <Navbar {...props} />
}

export default Header;
  • Navbar内使用props.path读取路径资料
    src/components/Navbar/Navbar.js
import React from 'react';
import styles from './Navbar.module.css';
import Navbar from 'react-bootstrap/Navbar';
import svgIcon from './navbaricon.svg';
import Nav from 'react-bootstrap/Nav';

const Topbar = (props) => {
  return (
    <Navbar className={styles.navbar}>
      <Navbar.Brand className={styles.title} href="/">
        <img
          alt=""
          src={svgIcon}
          width="30"
          height="30"
          className="d-inline-block align-top"
        />{' '}Invsetment Dashboard
      </Navbar.Brand>
      <Navbar.Collapse id="responsive-navbar-nav">
        <Nav className="me-auto" activeKey={props.path}>
          <Nav.Link href="/" className={styles.link}><p>首页</p></Nav.Link>
          <Nav.Link href="/macroeconomics" className={styles.link}><p>总体经济</p></Nav.Link>
        </Nav>
      </Navbar.Collapse>
    </Navbar>
  );
};

export default Topbar;

小结

总之绕了好一大圈,终於将路径资料传递到Navbar里面了,架构上看起来稍微复杂了一些,不过是为了後续维护上的方便度,才使用这样的架构,还算是可以接受。目前首页还是没有内容的,接下来就来做一下首页吧~


<<:  Day 18 - 未知与空值 undefined、null、NaN

>>:  [Angular] Day33. Communicating with backend services using HTTP

2021最新Canonical终极指南,短短的语法让你的SEO功力倍增提升网站能见度

Canonical 是什麽 图片来源:https://www.samunderwood.co.uk/...

CSS微动画 - Transform不一定是位移的最佳选择

Q: 效能跟效果之间怎麽取舍? A: 如果效果不复杂,用一些渲染成本比较高的写法也无妨 新属性搭配...

[DAY 21]纠团通知功能(1/3)

先前做的公会文字云 其中任务、副本、主线的出现次数很多代表频道里蛮常有人想纠团的 但我翻了一下纪录成...

Day 30: 遗漏的章节

「目前为止,所有建议无疑将帮助你设计出更好的软件,这些软件是由具有明确边界、职责、依赖关系受控的元...

Day30:今天来聊一下如何使用 Azure Sentinel 搜捕威胁

了解如何使用 Azure Sentinel中的Jupyter Notebook进行先进搜寻。 在我们...