Всем привет! Шмодзи здесь! Сегодня я научу вас, как создать работающую панель навигации с помощью React. Панель навигации, на которой я сосредоточен, будет боковой панелью, потому что на этот раз я не хотел сосредотачиваться на заголовке. Однако в проекте будет функционирующий заголовок, как вы видите на рисунке ниже.

Этот урок следует за моим Учебником YouTube. Если вам просто нужен код, вот репозиторий GitHub и, пожалуйста, следуйте, если это поможет.

Прежде всего, вам нужно открыть командную строку и убедиться, что вы загрузили npm:

npm --version

Вы можете скачать npm здесь.

Теперь перейдите в папку, в которой вы хотите сохранить свой проект. Я храню свой в папке ReactWorkspace:

cd ReactWorkspace

Создайте свое приложение React:

npm init react-app navbar-tut

После этого вы хотите открыть свой проект в IDE. Я использую Visual Studio Code (VSC), потому что это потрясающе, но не стесняйтесь использовать все, что вам нравится. Если вы используете VSC, откройте свой проект, набрав:

cd navbar-tut
code .

Итак, у нас есть базовый шаблон приложения React. Чтобы запустить веб-приложение и посмотреть, как выглядит ваш текущий веб-сайт, введите это в свой терминал:

npm start

Браузер появляется, показывая, что он работал, ура. Пришло время настроить некоторые базовые вещи.

Зайдите в package.json и вставьте туда эти зависимости:

"bootstrap": "^4.3.1",
"react": "^16.10.2",
"react-bootstrap": "^1.0.0-beta.14",
"react-dom": "^16.10.2",
"react-router-dom": "^5.0.1",
"react-scripts": "3.1.1",
"styled-components": "^4.3.2"

Теперь установите эти зависимости, открыв терминал и набрав:

npm install

Прохладный. Вставьте эту ссылку в тег ‹head› внутри index.html. Это для иконок Font Awesome:

<!-- Including Font Awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">

Помните тот заголовок, о котором я говорил ранее? Давайте добавим для этого код. Заголовок не нужен, но он хорошо смотрится с боковой панелью, которую мы делаем.

Щелкните правой кнопкой мыши папку src и создайте папку с именем components.

Щелкните правой кнопкой мыши папку components и создайте файл NavigationBar.js. Вставьте этот код:

import React from 'react';
import { Nav, Navbar, Form, FormControl } from 'react-bootstrap';
import styled from 'styled-components';
const Styles = styled.div`
  .navbar { background-color: #222; }
  a, .navbar-nav, .navbar-light .nav-link {
    color: #9FFFCB;
    &:hover { color: white; }
  }
  .navbar-brand {
    font-size: 1.4em;
    color: #9FFFCB;
    &:hover { color: white; }
  }
  .form-center {
    position: absolute !important;
    left: 25%;
    right: 25%;
  }
`;
export const NavigationBar = () => (
  <Styles>
    <Navbar expand="lg">
      <Navbar.Brand href="/">Tutorial</Navbar.Brand>
      <Navbar.Toggle aria-controls="basic-navbar-nav"/>
      <Form className="form-center">
        <FormControl type="text" placeholder="Search" className="" />
      </Form>
      <Navbar.Collapse id="basic-navbar-nav">
        <Nav className="ml-auto">
          <Nav.Item><Nav.Link href="/">Home</Nav.Link></Nav.Item> 
          <Nav.Item><Nav.Link href="/about">About</Nav.Link></Nav.Item>
        </Nav>
      </Navbar.Collapse>
    </Navbar>
  </Styles>
)

Теперь перейдите в App.js и добавьте соответствующий импорт:

import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { NavigationBar } from './components/NavigationBar';

Удалите все из возврата и добавьте это:

<React.Fragment>
  <Router>
    <NavigationBar />
  </Router>
</React.Fragment>

Сохраните и проверьте в браузере, есть ли там заголовок. Если есть заголовок, но он выглядит иначе, чем на картинке выше, попробуйте повторно загрузить зависимости. Всегда перезагружайте сервер после использования npm install.

Маршрутизация - это способ перехода от страницы к странице, поэтому вставьте приведенный ниже код в ‹Router›. В основном он говорит, что если на этом пути, визуализируйте этот компонент:

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route component={NoMatch} />
</Switch>

В настоящее время это нарушает работу приложения, потому что у нас нет этих компонентов. Итак, давайте добавим эти страницы, чтобы убедиться, что навигация будет работать. Код на этих страницах на самом деле не имеет значения, я просто добавляю случайные вещи, чтобы убедиться, что мы видим разницу на разных страницах.

Внутри src создайте Home.js и вставьте его внутрь:

import React from 'react';
import styled from 'styled-components';
const GridWrapper = styled.div`
  display: grid;
  grid-gap: 10px;
  margin-top: 1em;
  margin-left: 6em;
  margin-right: 6em;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: minmax(25px, auto);
`;
export const Home = (props) => (
  <GridWrapper>
    <p>This is a paragraph and I am writing on the home page</p>
    <p>This is another paragraph, hi hey hello whatsup yo</p>
  </GridWrapper>
)

Создайте About.js и вставьте его внутрь:

import React from 'react';
import styled from 'styled-components';
const GridWrapper = styled.div`
  display: grid;
  grid-gap: 10px;
  margin-top: 1em;
  margin-left: 6em;
  margin-right: 6em;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: minmax(25px, auto);
`; 
export const About = () => (
  <GridWrapper>
    <h2>About Page</h2>
    <p>State at ceiling lay on arms while you're using the keyboard so this human feeds me.</p>
    <p>I am a kitty cat, sup, feed me, no cares in the world</p>
    <p>Meow meow, I tell my human purr for no reason but to chase after</p>
  </GridWrapper>
)

Создайте NoMatch.js и вставьте его внутрь:

import React from 'react';
import styled from 'styled-components';
const Wrapper = styled.div`
  margin-top: 1em;
  margin-left: 6em;
  margin-right: 6em;
`;
export const NoMatch = () => (
  <Wrapper>
    <h2>No Match</h2>
  </Wrapper>
)

Теперь зайдите в App.js, импортируйте эти страницы, и боги маршрутизации будут счастливы.

import { Home } from './Home';
import { About } from './About';
import { NoMatch } from './NoMatch';

Зайдите в браузер и нажмите на ссылки в заголовке, чтобы увидеть, как работает маршрутизация!

Хорошо, теперь мы можем создать боковую панель. Я постараюсь объяснить этот код более подробно, вместо того, чтобы просто вставлять его и оставлять вам разбираться в нем.

Внутри компонентов создайте Sidebar.js

Мы знаем, что хотим создать компонент боковой панели и экспортировать его для использования внутри App.js. Поместите это в Sidebar.js:

import React from 'react';
export default class Sidebar extends React.Component {
  render() {
    return (
    
    );
  }
}

В основном это говорит: пожалуйста, экспортируйте это как компонент React по умолчанию, и все, что мы поместим в return, будет отрисовано.

Вставьте приведенный ниже код в возврат:

<SideNav></SideNav>

Это компонент SideNav, который еще не создавался. Давай создадим это. Вставьте это над классом боковой панели:

class SideNav extends React.Component {
}

Это в основном говорит: создайте новый компонент. Иногда вы услышите, что он называется компонентом React, классом ES6 или просто компонентом класса.

Добавьте рендер и вернитесь в SideNav:

render() {
  return (
  
  );
}

Итак, как мы хотим, чтобы наш SideNav выглядел? НУ, мы хотим, чтобы по экрану шла черная полоса. Это означает, что мы попадаем в область HTML и CSS.

Я должен сообщить вам, что мне нравится использовать стилизованные компоненты для стилизации в React. Он полностью отличается от встроенных стилей, поэтому я рекомендую вам следовать им и не использовать свой собственный стиль.

Во-первых, давайте импортируем styled-components. Он позволяет создавать теги, управляющие собственным CSS. Теперь создайте StyledSideNav:

import styled from "styled-components";
/* This defines the actual bar going down the screen */
const StyledSideNav = styled.div`
  position: fixed;     /* Fixed Sidebar (stay in place on scroll and position relative to viewport) */
  height: 100%;
  width: 75px;     /* Set the width of the sidebar */
  z-index: 1;      /* Stay on top of everything */
  top: 3.4em;      /* Stay at the top */
  background-color: #222; /* Black */
  overflow-x: hidden;     /* Disable horizontal scroll */
  padding-top: 10px;
`;

Это руководство не о CSS, поэтому просто прочтите мои комментарии или Google, если что-то не понимает.

Теперь поместите ‹StyledSideNav› в возврат ‹SideNav› и сохраните:

<StyledSideNav></StyledSideNav>

Чтобы увидеть это в браузере, импортируйте его в App.js:

import Sidebar from './components/Sidebar';

Разместите ‹Sidebar› прямо под ‹NavigationBar /›:

<Sidebar />

Милая, у нас есть боковая панель!

Теперь давайте добавим несколько интерактивных значков.

Я хотел бы сделать это с помощью div NavItem, который содержит div NavIcon. Может быть, есть способ получше, но я сделаю так.

Поначалу это может не иметь смысла, но, откровенно говоря, со мной все сложится.

Итак, создайте компонент NavItem следующим образом:

class NavItem extends React.Component {
  render() {
    return (
    );
  }
}

Внутри рендера, но над return введите:

const { active } = this.props;

Это получает активную переменную из свойств NavItem. Если вы не знаете, что такое реквизит, вам лучше погуглить, друг.

Чтобы использовать навигацию, импортируйте необходимые данные:

import { BrowserRouter as Router, Route, Link } from "react-router-dom";

Внутри возврата NavItem добавьте следующее:

<StyledNavItem active={active}>
  <Link to={this.props.path} className={this.props.css} onClick={this.handleClick}>
    <NavIcon></NavIcon>
  </Link>
</StyledNavItem>

Если вы посмотрите на реквизиты на ‹Link›, to - это путь, по которому нужно перейти, className передает CSS для значка Font Awesome и onClick вызовет метод handleClick (). Давайте создадим этот метод. Поместите это выше рендера:

handleClick = () => {
  const { path, onItemClick } = this.props;
  onItemClick(path);
}

Эта стрелочная функция получает path и onItemClick из свойств NavItem, а затем вызывает onItemClick ().

Потрясающие. Итак, в настоящее время это не сработает, так что давайте поработаем еще немного. Добавьте NavIcon. Я оставляю его пустым, но добавляю любой нужный CSS:

const NavIcon = styled.div`
`;

Создайте StyledNavItem. Тег ‹Link› использует привязку, поэтому используется селектор привязки. Единственная запутывающая часть CSS - это часть, в которой используются реквизиты. Он говорит: используя свойство active, решите, какой из цветов выбрать. Итак, если домашняя страница активна, сделайте значок домашней страницы белым:

const StyledNavItem = styled.div`
  height: 70px;
  width: 75px; /* width must be same size as NavBar to center */
  text-align: center; /* Aligns <a> inside of NavIcon div */
  margin-bottom: 0;   /* Puts space between NavItems */
  a {
    font-size: 2.7em;
    color: ${(props) => props.active ? "white" : "#9FFFCB"};
    :hover {
      opacity: 0.7;
      text-decoration: none; /* Gets rid of underlining of icons */
    }  
  }
`;

Итак ... откуда у нашего NavItem все эти реквизиты? Что ж, мы еще не сделали эту часть ... так что давайте сделаем это!

Зайдите в SideNav. Мы хотим, чтобы SideNav был компонентом с отслеживанием состояния. Это связано с тем, что ему необходимо сохранить текущий путь и на основе этого решить, какой значок следует выбрать и окрасить в белый цвет.

Создайте конструктор. Там создайте состояние, которое содержит activePath, который мы сейчас установим как домашний путь, и items, содержащий информацию для наших выбираемых значков:

constructor(props) {
  super(props);
  this.state = {
    activePath: '/',
    items: [
      {
        path: '/', /* path is used as id to check which NavItem is active basically */
        name: 'Home',
        css: 'fa fa-fw fa-home',
        key: 1 /* Key is required, else console throws error. Does this please you Mr. Browser?! */
      },
      {
        path: '/about',
        name: 'About',
        css: 'fa fa-fw fa-clock',
        key: 2
      },
      {
        path: '/NoMatch',
        name: 'NoMatch',
        css: 'fas fa-hashtag',
        key: 3
      },
    ]
  }  
}

Итак, вы помните, как раньше нам нужно было передать функцию onItemClick () в NavItem в качестве опоры? Теперь давайте создадим это в нашем конструкторе:

onItemClick = (path) => {
  this.setState({ activePath: path }); /* Sets activePath which causes rerender which causes CSS to change */
}

Весь этот код говорит, что измените activePath, установив состояние. Если вы не знаете, всякий раз, когда вы вызываете setState (), React будет повторно визуализировать ваш компонент, что отобразит изменение, чтобы показать, что вы выбрали другой значок.

Последнее, и жизнь должна быть хорошей. Обычно я рекомендую не проводить так долго, не проверяя ошибки, но здесь я делаю именно это.

Измените свой рендер, чтобы он выглядел так:

render() {
  const { items, activePath } = this.state;
  return (
    <StyledSideNav>
      {
        /* items = just array AND map() loops thru that array AND item is param of that loop */
        items.map((item) => {
          /* Return however many NavItems in array to be rendered */
          return (
            <NavItem path={item.path} name={item.name} css={item.css} onItemClick={this.onItemClick} /* Simply passed an entire function to onClick prop */ active={item.path === activePath} key={item.key}/>
          )
        })
      }
    </StyledSideNav>
  );
}

Перед возвратом из состояния извлекаются элементы и activePath. Чтобы отобразить все элементы NavItem, мы перебираем все элементы в цикле с помощью map ().

WAM, теперь у вас должна быть боковая панель с красивой навигацией.

Однако… есть еще одна проблема. Если вы открываете любую страницу в своем веб-приложении, по умолчанию всегда используется значок домашней страницы. Например, если вы введете маршрут / about в URL-адрес и выполните поиск, значок домашней страницы все равно будет выбран.

Итак, нам нужно изменить activePath в конструкторе на текущий путь. Поскольку боковая панель не находится внутри ‹Route›, это немного сложнее, но не так уж плохо.

Внутри Sidebar.js импортируйте withRouter ():

import { BrowserRouter as Router, Route, Link, withRouter } from "react-router-dom";

Создайте компонент под SideNav, который обертывает SideNav:

const RouterSideNav = withRouter(SideNav);

Теперь используйте ‹RouterSideNav› внутри боковой панели вместо обычного ‹SideNav›.

Теперь у вас есть доступ к props.location.pathname. Только дети ‹Route› имеют доступ без withRouter (). Внутри SideNav измените activePath:

activePath: props.location.pathname,

Сохраните его, и все готово. Холодные бобы!

Имея базовые знания HTML и CSS, вы также можете добавить текст под свои значки, как на картинке ниже, но для краткости я не буду этого делать:

Надеюсь, я смог помочь вам сегодня. Если да, не стесняйтесь хлопать в ладоши, делиться или подписываться. Если у вас есть какие-либо вопросы, прокомментируйте их ниже, и я посмотрю, что я могу сделать.

Шмодзи вон!

🐱‍👤 Следите за моими социальными сетями, чтобы быть в курсе:

YouTube, Twitter, Twitch