its*_*old 4 web-applications reactjs react-router progressive-web-apps
我想让我的网络应用程序像移动应用程序一样工作。这意味着当用户按回时,他们希望弹出窗口关闭,而不是整个页面发生变化。
我的最终目标是让它在模态打开时后退按钮现在将关闭模态,如果他们再次单击它会返回。
我尝试了几种方法,尽管很接近,但它们从未始终如一地响应。 https://codesandbox.io/s/github/subwaymatch/react-disable-back-button-example-v2
任何人都有我正在寻找的经过验证的工作版本?
您可以尝试在 URL 中使用哈希。哈希是以主题标签开头的 URL 段。在哈希之间导航通常不会触发任何页面加载,但仍然会向浏览器历史记录推送一个条目,使后退按钮能够关闭模式/弹出窗口。
// www.example.com#modal
window.location.hash // -> "#modal"
Run Code Online (Sandbox Code Playgroud)
您的显示和隐藏模式状态基于window.location.hash.
您可以创建一个像这样的钩子(仅用于抽象)
function useHashRouteToggle(modalHash) {
const [isOpen, toggleOpen] = useState(false);
const toggleActive = (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);
}, [modalHash]);
return [isActive, toggleActive];
}
Run Code Online (Sandbox Code Playgroud)
然后在弹出窗口/模式中使用它。
const [isActive, toggleActive] = useHashRouteToggle('#modal');
const openModal = () => toggleActive(true);
<Modal isShow={isActive} />
Run Code Online (Sandbox Code Playgroud)
这样,您无需修改或覆盖浏览器行为即可实现您的需求。上面的代码只是对您可以执行的操作的抽象。您可以根据您的需要对其进行改进。希望它能给你一些想法。
实际上,我相信后退功能对用户体验很有用,但对于模态打开/关闭,您是对的。浏览器的后退按钮应关闭桌面和移动设备中的模式。我建议您编写两个辅助函数,一个用于取消浏览器后退按钮,然后运行您自己的功能,另一个用于恢复浏览器后退按钮。使用neutralizeBack时,一个模式被打开功能和使用revivalBack功能,当开启模式被关闭。使用第二个回到我对浏览器后退按钮功能的用户体验的态度。
本neutralizeBack应该运行的回调函数。这个回调函数是你想要做的:
const neutralizeBack = (callback) => {
window.history.pushState(null, "", window.location.href);
window.onpopstate = () => {
window.history.pushState(null, "", window.location.href);
callback();
};
};
Run Code Online (Sandbox Code Playgroud)
revivalBack当您想恢复浏览器后退按钮功能时,应该运行:
const revivalBack = () => {
window.onpopstate = undefined;
window.history.back();
};
Run Code Online (Sandbox Code Playgroud)
用法示例:
handleOpenModal = () =>
this.setState(
{ modalOpen: true },
() => neutralizeBack(this.handleCloseModal)
);
handleCloseModal = () =>
this.setState(
{ modalOpen: false },
revivalBack
);
Run Code Online (Sandbox Code Playgroud)
为了使后退按钮在模态关闭时起作用,您需要在打开模态时推送一条路线,并且在关闭时可以使用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>
);
}
Run Code Online (Sandbox Code Playgroud)
作为参考,请查看React router 模态库示例
| 归档时间: |
|
| 查看次数: |
6548 次 |
| 最近记录: |