Управление кнопкой «Назад» в React - PullRequest
1 голос
/ 24 марта 2020

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

Моя конечная цель - сделать так, чтобы при открытии модального режима кнопка «Назад» теперь закрывала модальный режим и, если они нажимали это снова будет go назад.

Я пробовал несколько методов, и хотя близко, они никогда не отвечают последовательно. https://codesandbox.io/s/github/subwaymatch/react-disable-back-button-example-v2

Кто-нибудь с ПРОВЕРЕННОЙ рабочей версией того, что я ищу?

Ответы [ 3 ]

4 голосов
/ 27 марта 2020

Вы можете попробовать использовать ha sh в своем URL. Ха sh - это сегмент URL, начинающийся с хэштега. Навигация между ha sh обычно не запускает загрузку страницы, но все же pu sh запись в истории браузера, которая позволяет кнопке назад закрывать модальное / всплывающее окно.

// www.example.com#modal
window.location.hash // -> "#modal"

Ваше модальное состояние показ и сокрытие основаны на window.location.hash.

. Вы можете создать крючок примерно так (только для абстракции)

function useHashRouteToggle(modalHash) {
  const [isOpen, toggleOpen] = useState(false);

  const toggleOpenModal = (open) => {
    if (open) {
      window.location.assign(modalHash); // navigate to same url but with the specified hash
    } else {
      window.location.replace('#'); // remove the hash
    }
  }

  useEffect(() => { 
    // function for handling hash change in browser, toggling modal open 
    const handleOnHashChange = () => {  
      const isHashMatch = window.location.hash === modalHash;   
      toggleOpen(isHashMatch);  
    };  

    // event listener for hashchange event
    window.addEventListener('hashchange', handleOnHashChange);  

    return () => window.removeEventListener('hashchange', handleOnHashChange);  
  }, [hashRoute]);

  return [isActive, toggleActive];
} 

Затем используйте его в своем всплывающем окне / модале.

const [isActive, toggleActive] = useHashRouteToggle('#modal');

const openModal = () => toggleActive(true);

<Modal isShow={isActive} />

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

2 голосов
/ 27 марта 2020

Для того, чтобы кнопка "Назад" работала на закрытии модала, вам нужно выбрать sh маршрут, при открытии модального окна и закрыть, вы можете использовать history.goBack (). Может быть этот пример может быть полезным.

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  useHistory,
  useLocation,
  useParams
} from "react-router-dom";

export default function ModalGalleryExample() {
  return (
    <Router>
      <ModalSwitch />
    </Router>
  );
}

function ModalSwitch() {
  let location = useLocation();
  let background = location.state && location.state.background;
  return (
    <div>
      <Switch location={background || location}>
        <Route exact path="/" children={<Gallery />} />
        <Route path="/img/:id" children={<ImageView />} />
      </Switch>
      {background && <Route path="/img/:id" children={<Modal />} />}
    </div>
  );
}

const IMAGES = [
  { id: 0, title: "Dark Orchid", color: "DarkOrchid" },
  { id: 1, title: "Lime Green", color: "LimeGreen" },
  { id: 2, title: "Tomato", color: "Tomato" },
  { id: 3, title: "Seven Ate Nine", color: "#789" },
  { id: 4, title: "Crimson", color: "Crimson" }
];

function Thumbnail({ color }) {
  return (
    <div
      style={{
        width: 50,
        height: 50,
        background: color
      }}
    />
  );
}

function Image({ color }) {
  return (
    <div
      style={{
        width: "100%",
        height: 400,
        background: color
      }}
    />
  );
}

function Gallery() {
  let location = useLocation();

  return (
    <div>
      {IMAGES.map(i => (
        <Link
          key={i.id}
          to={{
            pathname: `/img/${i.id}`,
            // This is the trick! This link sets
            // the `background` in location state.
            state: { background: location }
          }}
        >
          <Thumbnail color={i.color} />
          <p>{i.title}</p>
        </Link>
      ))}
    </div>
  );
}

function ImageView() {
  let { id } = useParams();
  let image = IMAGES[parseInt(id, 10)];

  if (!image) return <div>Image not found</div>;

  return (
    <div>
      <h1>{image.title}</h1>
      <Image color={image.color} />
    </div>
  );
}

function Modal() {
  let history = useHistory();
  let { id } = useParams();
  let image = IMAGES[parseInt(id, 10)];

  if (!image) return null;

  let back = e => {
    e.stopPropagation();
    history.goBack();
  };

  return (
    <div
      onClick={back}
      style={{
        position: "absolute",
        top: 0,
        left: 0,
        bottom: 0,
        right: 0,
        background: "rgba(0, 0, 0, 0.15)"
      }}
    >
      <div
        className="modal"
        style={{
          position: "absolute",
          background: "#fff",
          top: 25,
          left: "10%",
          right: "10%",
          padding: 15,
          border: "2px solid #444"
        }}
      >
        <h1>{image.title}</h1>
        <Image color={image.color} />
        <button type="button" onClick={back}>
          Close
        </button>
      </div>
    </div>
  );
}

Для справки, пожалуйста, проверьте пример реакции модальной галереи маршрутизатора

0 голосов
/ 30 марта 2020

На самом деле, я считаю, что обратная функциональность полезна для пользовательского опыта, но для модального открыть / закрыть вы правы. кнопка возврата в браузерах должна закрывать модальное положение как на настольных компьютерах, так и на мобильных устройствах. Я предлагаю вам написать две вспомогательные функции, одну для нейтрализации кнопки возврата браузера, затем запустить собственную функциональность и одну для возрождения кнопки возврата браузера. используйте функцию neutralizeBack, когда модал открыт, и используйте функцию revivalBack, когда этот модал закрыт. использование второго возвращает меня к восприятию пользователем функциональности кнопки возврата браузера.

  • neutralizeBack должен запускать функцию обратного вызова. эта функция обратного вызова - то, что вы хотите сделать:

    const neutralizeBack = callback => {
      window.history.pushState(null, "", window.location.href);
      window.onpopstate = () => {
        window.history.pushState(null, "", window.location.href);
        callback();
      };
    };
    
  • revivalBack должен запускаться, когда вы хотите восстановить функциональность кнопки возврата браузера:

    const revivalBack = () => {
      window.onpopstate = undefined;
      window.history.back();
    };
    

Пример использования:

handleOpenModal = () =>
  this.setState(
    { modalOpen: true },
    () => neutralizeBack(this.handleCloseModal)
  );

handleCloseModal = () =>
  this.setState(
    { modalOpen: false },
    revivalBack
  );
...