Отзывчивые навигационные панели являются одними из хлеба и масла фронтенд-разработки. Обычной практикой является панель навигации на рабочем столе и боковая панель на мобильных устройствах. Вероятно, это очень легко реализовать с помощью ваших любимых фреймворков CSS. Тем не менее, это оказывается либо довольно сложным, либо совершенно сложным при использовании фреймворка semantic-UI-react (который, за исключением этой маленькой причуды, является удивительным фреймворком). Эта статья представляет собой демонстрацию того, как создать адаптивную панель навигации с помощью React, Semantic-UI-React и React-Response, поскольку на момент написания практически не было готовых решений.

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

В конце этой статьи вы узнаете, как:

  • сделать отзывчивую панель навигации с помощью semantic-UI-react CSS framework
  • используйте пакет react-responsive

Что такое Semantic-UI-реакция?

Semantic UI — один из многих популярных фреймворков CSS, которые якобы ускоряют создание веб-сайтов, предоставляя нам уже готовые компоненты CSS. Он гордится тем, что является семантическим, что в основном достигается за счет использования продуманных и осмысленных имен классов. Теперь, после использования таких фреймворков, как bootstrap и tailwind, я должен признать, что четкие, продуманные имена классов стали весьма ценными!

Фреймворк semantic-UI-react является расширением CSS-фреймворка semantic-UI, оптимизированным для работы с реакцией и использования системы поддержки реакции (так же, как у нас есть bootstrap и react-bootstrap). И это работает как шарм, пока вам не нужно создать отзывчивую панель навигации.

Что такое React-Responsive?

React-responsive — это пакет, который позволяет нам динамически вводить и удалять контент, отображаемый React в данный момент на экране, в зависимости от размера области просмотра. Используя этот пакет, мы можем имитировать медиа-запросы CSS-экрана непосредственно в коде реакции. Это мой любимый инструмент для адаптивного дизайна в React. Не стесняйтесь использовать любой альтернативный пакет, который может воспроизвести ту же функциональность.

Настраивать

Для начала:

  • запустить приложение React (в этой демонстрации используется vite-react)
  • очистите приложение, чтобы оно соответствовало файловой структуре на картинке ниже

  • Установите пакеты semantic-UI-react, semantic-UI-CSS и пакеты, реагирующие на реакцию, с помощью NPM.
  • Добавьте любое изображение логотипа по вашему выбору в общую папку
  • Импортируйте semantic.min.css в main.jsx. Этот импорт должен быть выше index.css, чтобы мы могли использовать index.css для перезаписи некоторых встроенных стилей семантической реакции пользовательского интерфейса, если это необходимо.
  • Добавьте следующие строки кода в указанные компоненты
/*index.css*/
  body {
      background-color: rgb(35, 35, 141)
  }


  //app.jsx
  import Navbar from "./components/navbar"
  function App() {
    return (
      <div className="App">
        <Navbar />
      </div>
    )
  }
  export default App


  //Main.jsx
  import React from 'react'
  import ReactDOM from 'react-dom/client'
  import App from './App'
  import 'semantic-ui-css/semantic.min.css'
  import './index.css'
  
  ReactDOM.createRoot(document.getElementById('root')).render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  )

Компонент NavbarLg

Мы будем использовать компонент меню для панели навигации на больших экранах. Для этого посетите semantic-UI-react docs и выберите предпочитаемый тип компонента меню. В этой демонстрации будет использоваться инвертированный тип меню.

  • Документы написаны с использованием компонентов класса React, но это довольно простой код, поэтому я преобразую его в функциональный компонент.
  • Мы также добавим ссылку для регистрации и входа в правый край панели навигации.
import { useState} from 'react'
import { Menu, Segment } from 'semantic-ui-react'
export default function NavbarLg() {
  const [activeItem,setactiveItem]=useState("home")
  const handleItemClick = (e, { name }) => setactiveItem(name)
    return (
      <Segment inverted attached size='mini'>
        <Menu inverted secondary>
          <Menu.Item
            name='logo'
            active={activeItem === 'logo'}
            onClick={handleItemClick}
          >
            <img src="ghostblog.svg"  alt="" />
          </Menu.Item>
          <Menu.Item
            name='home'
            active={activeItem === 'home'}
            onClick={handleItemClick}
          />
          <Menu.Item
            name='messages'
            active={activeItem === 'messages'}
            onClick={handleItemClick}
          />
          <Menu.Item
            name='friends'
            active={activeItem === 'friends'}
            onClick={handleItemClick}
          />
          
          <Menu.Item
            name='login'
            active={activeItem === 'login'}
            onClick={handleItemClick}
            position="right"
          />
          <Menu.Item
            name='sign_in'
            active={activeItem === 'sign_in'}
            onClick={handleItemClick}
          />
          {/* section */}
        </Menu>
      </Segment>
    )
  }


//navbar.jsx 
import NavbarLg from "./NavbarLg"
export default function Navbar() {
  return (
    <div>
        <NavbarLg/>
    </div>
  )
}

Компонент NavbarMb

Переходя к мобильной панели навигации, мы будем использовать боковую панель semantic-UI-react (см. https://react.semantic-ui.com/modules/sidebar/), но внесем в нее некоторые серьезные изменения.

Проблема заключается в том, как семантический пользовательский интерфейс добавил оверлей, который вынуждает весь остальной контент на странице находиться в компоненте sidebar.pusher. Это неэффективно, учитывая, что мы не хотели бы вкладывать весь контент нашего приложения в этот компонент. Кроме того, элементы управления боковой панели нуждаются в доработке, так как значок гамбургера был бы гораздо предпочтительнее, чем галочка. Чтобы исправить все это, мы добавим три пользовательских компонента.

  1. Компонент тонированного наложения
  2. Значок гамбургера, чтобы открыть боковую панель
  3. Значок закрытия, чтобы закрыть боковую панель

Примечание: мы будем использовать встроенные значки семантического интерфейса.

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

//NavbarMb.jsx
import { useState } from 'react'
import { Menu, Sidebar } from 'semantic-ui-react'
function Overlay() {
  return (
    <div style={{
      backgroundColor: "rgba(0, 0, 0, 0.795)",
      position: "fixed",
      height: "110vh",
      width: "100%",
    }} />
  )
}

function HamIcon() {
  return (<i className="big bars icon inverted" />)
}

function CloseIcon() {
  return (<i className="big close red icon" />)
}
function NavbarMb({renderLinks}) {
  const [visible, setVisible] = useState(false)
  const [icon, setIcon] = useState(HamIcon)
  const [activeItem, setactiveItem] = useState("home")
  const handleItemClick = (e, { name }) => setactiveItem(name)
  const hideSidebar = () => {
    setIcon(HamIcon)
    setVisible(false)
  }
  const showSidebar = () => {
    setIcon(CloseIcon)
    setVisible(true)
  }
  const toggleSidebar = () => {
    visible ? hideSidebar() : showSidebar()
  }
  return (
    <>
      {visible && <Overlay />}
      <Menu inverted
        size="tiny"
        borderless
        attached
      >
        <Menu.Item>
          <img src="ghostblog.svg" width="35px" height="35px" alt="" />
        </Menu.Item>
        <Menu.Menu position='right'>
          <Menu.Item onClick={toggleSidebar}>
            {icon}
          </Menu.Item>
        </Menu.Menu>
      </Menu>
      <Sidebar as={Menu}
        animation='overlay'
        icon='labeled'
        inverted
        vertical
        visible={visible}
        width='thin'
      >
        <Menu.Item>
          <img src="ghostblog.svg" width="35px" height="35px" style={{ margin: "0 auto" }} alt="" />
        </Menu.Item>
        <Menu.Item
          name='home'
          active={activeItem === 'home'}
          onClick={handleItemClick}
        />
        <Menu.Item
          name='messages'
          active={activeItem === 'messages'}
          onClick={handleItemClick}
        />
        <Menu.Item
          name='friends'
          active={activeItem === 'friends'}
          onClick={handleItemClick}
        />
        <Menu.Item
          name='login'
          active={activeItem === 'login'}
          onClick={handleItemClick}
          position="right"
        />
        <Menu.Item
          name='sign_in'
          active={activeItem === 'sign_in'}
          onClick={handleItemClick}
        />
      </Sidebar>
    </>
  )
}

export default NavbarMb


//navbar.jsx 
import NavbarMb from "./NavbarMb"
import NavbarLg from "./NavbarLg"
export default function Navbar() {
  return (
    <div>
        {/*<NavbarLg/>*/}
        <NavbarMb/>
    </div>
  )
}

Повтор сеанса с открытым исходным кодом

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

Начните получать удовольствие от отладки — начните использовать OpenReplay бесплатно.

Делаем навигационную панель отзывчивой с помощью React-responsive

У нас есть навигационная панель для большого экрана и одна для мобильного экрана. Давайте поработаем с react-responsive, чтобы сделать панель навигации отзывчивой, переключаясь с navbar-large на navbar-mobile и наоборот в зависимости от размера экрана.

Мы сделаем это в компоненте навигационной панели, используя отзывчивый ответ.

  • Импортируйте NavbarLg и NavbarMb в компонент Navbar
  • Следуя отзывчивым документам, объявите несколько точек останова как переменные, используя хук useMediaQuery.
  • Создайте объект размеров экрана из точек останова
  • Отображение компонента NavbarLg или NavbarMb условно в зависимости от того, превышает ли размер экрана точку останова или нет

Примечание. Этот пакет (реагирующий на реакцию) довольно прост в использовании, и документация очень ясно описывает, как его использовать.

//navbar.jsx
import { useMediaQuery } from 'react-responsive'
import NavbarMb from "./NavbarMb"
import NavbarLg from "./NavbarLg"
export default function Navbar() {
  
  const none =useMediaQuery({ query: "(max-width:576px)" }) 
  const sm = useMediaQuery({ query: "(min-width:576px)" })
  const md = useMediaQuery({ query: "(min-width:768px)" })
  const lg = useMediaQuery({ query: "(min-width:992px)" })
  const xl = useMediaQuery({ query: "(min-width:1200px)" })
  const xxl = useMediaQuery({ query: "(min-width:1400px)" })
  const size = {none,sm,md,lg,xl,xxl}
  return (
    <div>
        {size.sm ? <NavbarLg /> : <NavbarMb /> }
    </div>
  )
}

Вроде все закончили, но не совсем. Если вы посмотрите достаточно внимательно, вы заметите, что состояние не сохраняется после перехода с большой панели навигации на мобильную панель навигации. Это видно по выделенному nav-link, который снова меняется на home, когда мы переключаемся с большой панели навигации на мобильную панель навигации и наоборот.

Теперь представьте, что это многостраничное приложение React. Это, вероятно, приведет к путанице, поскольку, если кто-то на странице входа свернет свой экран, панель навигации вернется к выделению home, даже если приложение останется на странице входа.

Чтобы исправить это,

  • мы поднимем состояние nav-links до основного компонента Navbar и будем обрабатывать клики оттуда.
  • Затем nav-links можно передать NavbarLg или NavbarMb в качестве реквизита. Это сохранит состояние, поскольку nav-links являются частью компонента Navbar, а компонент Navbar всегда будет присутствовать в нашем пользовательском интерфейсе на больших и малых экранах.
//navbar.jsx
import { useState} from 'react'
import { useMediaQuery } from 'react-responsive'
import { Menu } from 'semantic-ui-react'
import NavbarMb from "./NavbarMb"
import NavbarLg from "./NavbarLg"
export default function Navbar() {
  const [activeItem,setactiveItem]=useState("home")
  const handleItemClick = (e, { name }) => setactiveItem(name)
  const renderLinks=()=>{
    return <><Menu.Item
    name='logo'
    active={activeItem === 'logo'}
    onClick={handleItemClick}
  >
    <img src="ghostblog.svg"  width="35px" height="35px" style={{ margin: "0 auto" }}  alt="" />
  </Menu.Item>
  <Menu.Item
    name='home'
    active={activeItem === 'home'}
    onClick={handleItemClick}
  />
  <Menu.Item
    name='messages'
    active={activeItem === 'messages'}
    onClick={handleItemClick}
  />
  <Menu.Item
    name='friends'
    active={activeItem === 'friends'}
    onClick={handleItemClick}
  />
  <Menu.Item
    name='login'
    active={activeItem === 'login'}
    onClick={handleItemClick}
    position="right"
  />
  <Menu.Item
    name='sign_in'
    active={activeItem === 'sign_in'}
    onClick={handleItemClick}
  />
  </>
  }
  
  const none =useMediaQuery({ query: "(max-width:576px)" }) 
  const sm = useMediaQuery({ query: "(min-width:576px)" })
  const md = useMediaQuery({ query: "(min-width:768px)" })
  const lg = useMediaQuery({ query: "(min-width:992px)" })
  const xl = useMediaQuery({ query: "(min-width:1200px)" })
  const xxl = useMediaQuery({ query: "(min-width:1400px)" })
  const size = {none,sm,md,lg,xl,xxl}
  return (
    <div>
        {size.sm ? <NavbarLg renderLinks={renderLinks}/> : <NavbarMb renderLinks={renderLinks}/> }
    </div>
  )
}


//NavbarLg.jsx
import { Menu, Segment } from 'semantic-ui-react'
export default function NavbarLg({renderLinks}) {
    return (
      <Segment inverted attached size='mini'>
        <Menu inverted secondary>
        {renderLinks()}
        </Menu>
      </Segment>
    )
  }



//Navbar.Mb
import { useState } from 'react'
import { Menu, Sidebar } from 'semantic-ui-react'
function Overlay() {
  return (
    <div style={{
      backgroundColor: "rgba(0, 0, 0, 0.795)",
      position: "fixed",
      height: "110vh",
      width: "100%",
    }} />
  )
}
function HamIcon() {
  return (<i className="big bars icon inverted" />)
}
function CloseIcon() {
  return (<i className="big close red icon" />)
}
function NavbarMb({renderLinks}) {
  const [visible, setVisible] = useState(false)
  const [icon, setIcon] = useState(HamIcon)
  const hideSidebar = () => {
    setIcon(HamIcon)
    setVisible(false)
  }
  const showSidebar = () => {
    setIcon(CloseIcon)
    setVisible(true)
  }
  const toggleSidebar = () => {
    visible ? hideSidebar() : showSidebar()
  }
  return (
    <>
      {visible && <Overlay />}
      <Menu inverted
        size="tiny"
        borderless
        attached
      >
        <Menu.Item>
          <img src="ghostblog.svg" width="35px" height="35px" alt="" />
        </Menu.Item>
        <Menu.Menu position='right'>
          <Menu.Item onClick={toggleSidebar}>
            {icon}
          </Menu.Item>
        </Menu.Menu>
      </Menu>
      <Sidebar as={Menu}
        animation='overlay'
        icon='labeled'
        inverted
        vertical
        visible={visible}
        width='thin'
      >
      {renderLinks()}
      </Sidebar>
    </>
  )
}

export default NavbarMb

Краткое содержание

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

Кроме того, благодаря тому, что компоненты реакции легко повторно использовать, компонент навигационной панели можно повторно использовать в нескольких проектах. С помощью стиля semantic-UI-react мы можем вносить соответствующие изменения и изменения в дизайн, чтобы он подходил для любого конкретного проекта.

Ресурсы

Первоначально опубликовано на https://blog.openreplay.com.