Major Edit: Я нашел два прекрасных видео, которые сделают что-то похожее на то, что сделал я, и оба созданы замечательным Максимилианом Шварцмюллером:

Пожалуйста, найдите ссылки:

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — -

Почему вы все еще хотите прочитать мою статью ниже:

Я реализовал общую навигационную панель, в которой есть раскрывающийся список и ссылки, за пределами click и React Hooks.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Изучив множество форумов, подобных StackOverflow, Github и другим, я нашел множество различных фреймворков, которые будут реализовывать для вас верхнюю навигационную панель. Но как скатать собственное?

Здесь нет единого решения, подходящего для всех. Но вы можете следовать моим инструкциям и сделать базовый, который даст вам хороший оптимальный опыт UI / UX.

На мой взгляд, есть несколько вещей, которые составляют хорошую навигационную панель:

  1. Навигационная панель верхнего положения
  2. Выпадающий список с несколькими горизонтальными рядами. Он есть на любом веб-сайте электронной коммерции, который вы видите. Например, на сайте Levis это есть

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

4. Когда вы нажимаете на другие ссылки или даже когда вы нажимаете за пределами, раскрывающийся список должен исчезнуть.

Затем есть несколько полезных вещей, которые я не предусмотрел, потому что они сильно сосредоточены на CSS.

5. Отзывчивая навигационная панель, когда экран маленький, они должны отображать гамбургер.

6. У активной ссылки должна быть какая-то идентификация.

7. Кнопка поиска

— — — — — — — — —

Итак, приступим:

Предварительные требования - ›Установленный узел и приложение Create-react-app.

Начнем с создания нового проекта.

Зайдите в свой терминал и создайте новый проект под названием navbar-react

$ create-react-app new-portfolio

Откройте этот проект в VScode или редакторе по вашему выбору. Я делаю это на VS Code, потому что мне очень нравится тема Draculla (https://draculatheme.com/visual-studio-code/)

Удалите общий код из App.js и App.css. Вот как выглядит ваш App.js после этого шага. Это будет моя первая фиксация в репо.

import React from 'react';
import './App.css';
function App() {
return (
<div>
</div>
);
}
export default App;

Мы создаем новую папку с именем Components под src и создаем новый файл с именем NavBar.js..

Установите материальный пользовательский интерфейс, чтобы придать структуре вашего приложения.

npm install --save @material-ui/core

import React, * as react from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
const NavBar = () => {
return (
<ul>
   <li>Projects</li>
   <div>
     <Dropdown />
   </div>
   <li>Blog</li>
   <li>Skills</li>
   <li>Story</li>
 </ul>
 );
};
export default NavBar;

Итак, как вы можете видеть, у нас есть 4 вкладки, первая - это раскрывающийся список, в котором мы хотим вызвать компонент Dropdown` (который мы закодируем позже), когда пользователь нажимает на первую вкладку.

Теперь, чтобы объявить раскрывающийся компонент, я объявил его внутри самого NavBar.js, но вы можете сделать это снаружи.

const Dropdown = () => {
  return (
   <Grid container>
     <Grid item xs={12} sm={2}>
       {''}
     </Grid>
     <Grid item xs={12} sm={2}>
      <h4>Web Dev</h4>
      <ul>
        <li>D3 World Map</li>
        <li>Keppler</li>
        <li>P5.js</li>
        <li>Gatsby</li>
     </ul>
    </Grid>
    <Grid item xs={12} sm={2}>
      <h4>Data Science</h4>
      <ul>
        <li>Data Mining</li>
        <li>Django web app</li>
        <li>Kaggle</li>
        <li>US Phone Complaints</li>
     </ul>
    </Grid>
    <Grid item xs={12} sm={2}>
      <h4>Design</h4>
      <ul>
        <li>Posters</li>
        <li>Sketch</li>
     </ul>
    </Grid>
    <Grid item xs={12} sm={2}>
      <h4>Video</h4>
      <ul>
        <li>Youtube Vlog</li>
      </ul>
    </Grid>
    <Grid item xs={12} sm={2}>
     <h4>Misc</h4>
    </Grid>
  </Grid>
  );
};

Теперь, когда у нас есть весь контент, нам нужно приступить к работе с функциями.

Перво-наперво, нам нужна навигационная кнопка для раскрытия раскрывающегося списка при нажатии и какая-то навигационная кнопка, чтобы напрямую перейти на другую страницу.

Чтобы добиться раскрывающегося списка, мы будем использовать возможности хуков и ловушку состояния.

В компоненте NavBar объявите обработчик состояния следующим образом:

const [listOpen, setListOpen] = react.useState(false);

Тогда ссылка, которую мы хотим сделать в раскрывающемся списке, будет иметь следующее:

onClick={()=>setListOpen(!listOpen)}

Мы сделаем компонент Dropdown заключенным в тернарное условие следующим образом

{listOpen?<Dropdown />:null}

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

onClick={()=>setListOpen(!false)}

Итак, компонент будет выглядеть так:

const NavBar = () => {
  const [listOpen, setListOpen] = react.useState(false);
  return (
    <ul>
      <li onClick={()=>setListOpen(!listOpen)}>Projects</li>
      <div>
        {listOpen?<Dropdown />:null}
      </div>
      <li onClick={()=>setListOpen(false)}>Blog</li>
      <li onClick={()=>setListOpen(false)}>Skills</li>
      <li onClick={()=>setListOpen(false)}>Story</li>
    </ul>
  );
};

Теперь нам нужно добавить страницы как разные ссылки на страницы. Для этого мы импортируем react-router-dom библиотеку.

npm install --save react-router-dom

Начнем с добавления <Router/> вокруг <App/> в index.js

ReactDOM.render(<Router><App /></Router>,document.getElementById('root');

В App.js добавьте информацию о маршрутах в функцию приложения:

function App() {
  return (
    <div>
      <NavBar />
      <Switch>
        <Route exact={true} path="/" component={Home} />
        <Route path="/home" component={Home} />
        <Route exact path="/blog" component={Blog} />
        <Route exact path="/skills" component={Skills} />
        <Route exact path="/story" component={Story} />
     </Switch>
   <p> FOOTER</p>
  </div>
 );
}

В компонент Navbar добавьте информацию Link в разделе li, так что теперь компонент <Navbar/> будет выглядеть так:

const NavBar = () => {
  const [listOpen, setListOpen] = react.useState(false);
  return (
    <ul>
      <li onClick={() => setListOpen(!listOpen)}>Projects</li>
        <div>{listOpen ? <Dropdown /> : null}</div>
      <li onClick={() => setListOpen(false)}>
        <Link to="/blog">Blog</Link>
      </li>
     <li onClick={() => setListOpen(false)}>
       <Link to="/skills">Skills</Link>
     </li>
     <li onClick={() => setListOpen(false)}>
       <Link to="/story">Story</Link>
     </li>
   </ul>
  );
};

Мы хотели бы добавить логотип на панель навигации, который будет отображаться слева, а остальные ссылки - справа. Поэтому добавьте изображение логотипа в папку public и добавьте img в свой Navbar компонент, добавив следующее над <ul>:

<Link to="/">
<img src={process.env.PUBLIC_URL + '/logo.png'} alt="Logo" />
</Link>

Теперь у нас есть полноценная функциональная панель навигации с раскрывающимся списком и маршрутизацией. Нам нужно сделать css для панели навигации, чтобы она действительно выглядела как панель навигации. Итак, я создал NavBar.style.css

.navbar {
  padding: 1% 4% 1% 9%;
  cursor: pointer;
  color: #0544f9;
}
.logo {
  height: 100px;
}
.navbar ul {
  padding-left: 500px;
  max-width: 100%;
  overflow-x: hidden;
  transition: 0.5s;
  border: none;
}
.navbar ul li {
  background-color: rgba(0, 0, 0, 000);
  border: 0;
  color: #0544f9;
  cursor: pointer;
  display: inline-table;
  font-size: 1.5rem;
  height: 3.28rem;
  line-height: 3.28rem;
  padding: 0 1.14rem;
  text-align: center;
  border-style: none;
}
.dropdown {
  position: fixed;
  margin: 5%;
  top: 100px;
  width: 70%;
  background-color: #ebebeb;
  color: #0544f9;
  cursor: pointer;
  opacity: 100;
}
.dropdown li {
  padding: 1% 12% 8% 2%;
  color: #0544f9;  
}

Наконец, мы добавляем ссылки в раскрывающиеся ссылки:

<ListItem>
  <Link to="/d3-world-map">D3 World Map</Link>
</ListItem>

А теперь пришло время "чего-нибудь хорошего".

Перво-наперво, когда мы щелкаем раскрывающийся список, он переводит нас на новую страницу, но мы хотим закрыть раскрывающийся список, когда вы находитесь на новой странице. Это должно быть легко, ведь мы должны просто поставить listOpen на false, верно? Ну да! это способ сделать это, за исключением того, что listOpen недоступен в Dropdown компоненте. Следовательно, нам нужно будет отправить набор обратного вызова listOpen в значение false, когда мы щелкнем по ссылке.

В компоненте Navbar установите метод обратного вызова с именем myCallback с listOpen в качестве параметра.

const myCallback = (listOpen) => {
  setListOpen(listOpen);
};

Объявите новую опору при возврате Dropdown компонента.

<Dropdown callbackFromParent={myCallback} />

Теперь в компоненте Dropdown передайте недавно объявленную опору и отправьте обратно listOpen как false.

const Dropdown = ({ callbackFromParent }) => {
  .
  .
  .
  <ListItem onClick={() => callbackFromParent(false)}>
    <Link to="/d3-world-map">D3 World Map</Link>
  </ListItem>
  .
  .
  .
}

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

Https://codesandbox.io/s/w62xl39907

Все, что нам нужно сделать, это добавить ссылку на узел в компоненте Dropdown.

<Grid container ref={node}>...</Grid>

Затем мы просто используем перехватчик Ref, чтобы понять и зафиксировать местоположение щелчка. Если он внутри, мы ничего не возвращаем, но если он снаружи, мы устанавливаем listOpen в false.

const Dropdown = ({ callbackFromParent }) => {
  const node = react.useRef();
  const handleClick = (e) => {
    if (node.current.contains(e.target)) {
      // inside click
      return;
    }
    // outside click
    callbackFromParent(false);
  };
 react.useEffect(() => {
  document.addEventListener('mousedown', handleClick);
  return () => {
    document.removeEventListener('mousedown', handleClick);
  };
 }, []);
 return(...);
}

Весь код доступен на моей странице Github и в ветке feat/navbar.



Ниже вы найдете полный компонент NavBar:

Надеюсь, вы найдете это полезным. Если вы хотите что-то изменить или у вас возникнут вопросы, отправьте сообщение / письмо по электронной почте.