刷新和關閉攔截
beforeunload 事件
觸發機制: 瀏覽器的刷新和關閉按鈕被點擊,點擊跳轉路由的按鈕 (全局生效)
偵聽機制: 頁面初始化和卸載時偵聽事件
缺點:
- 默認樣式,無法改變
- 全局生效
useEffect(()=>{
window.addEventListener('beforeunload', beforeunload);
},[])
useEffect(()=>{
window.addEventListener('beforeunload', beforeunload);
},[])
const beforeunload=(ev)=>{
if (ev) {
ev.returnValue = '';
}
}
返回、前進的彈框攔截
1.react-router-dom中的Prompt組件
觸發機制:瀏覽器的返回和前進按鈕被點擊(路由發生變化)
缺點: 不能自定義樣式
import React from 'react'
import {Prompt } from "react-router-dom"
export default function StopRoute(){
const [isOpen,setIsOpen]=useState(false)
const lanjieReturn=()=>{
(location)=>{
if(!isOpen) {
let leave = window.confirm("您確定要離開該頁面嗎?")
if(!leave) {
return false
}
}else {
setIsOpen(false)
/* 返回false是攔截的關鍵 */
return false
}
}
}
return (
<>
/* message是用來顯示內容的 when是用來控制攔截的時機的(也就是彈框出現的時機) */
<Prompt message="您確定要離開該頁面嗎?" when={isOpen} /> //第一種用法 message直接寫字符串
<Prompt //第二種用法 message是函數,但是函數內部只能是三木運算,且不用return (其實質也就是用法一的直接寫字符串)
message = {() => {
this.state.isOpen? false: "您確定要離開該頁面嗎?"
}}
<Prompt message = {lanjieReture}/> //第三種用法 mesage是函數,並且不是三目運算,則函數必須返回false,並且不能自定義彈框,因為react的顯示必須寫在render里面,這里的函數rentuen的是false,不是DOM,所以只能只用js的原生彈框來攔截
</>
)
}
2.useHistory().block
觸發機制: 瀏覽器的返回和前進按鈕被點擊
缺點:
- 用到的頁面,其組件在路由或者在任何地方不能使用高階組件(也就是不能再被別的組件包裹),否則失效
- 如果用到的頁面不是首頁,那么進來的頁面最好使用push,不能使用replace,否則不好使
import React, {useEffect, useState} from 'react';
import {useHistory} from 'react-router';
import Dialog from '@/components/Dialog'
export default function UserConfirmationTwo(props) {
const {when = false} = props;
const [isShowModal, setIsShowModal] = useState(false);
const history = useHistory();
const [nextLocation, setNextLocation] = useState(null);
const [action, setAction] = useState();
const [unblock, setUnblock] = useState(null);
useEffect(() => {
if (!when || unblock) {
return;
}
const cancel = history.block((nextLocation, action) => {
if (when) {
setIsShowModal(true);
}
setNextLocation(nextLocation);
setAction(action);
return false;
});
setUnblock(() => {
return cancel;
});
}, [when, unblock]);
useEffect(() => {
return () => {
unblock && unblock();
};
}, []);
function onConfirm() {
unblock && unblock();
if (action === 'PUSH') {
history.push(nextLocation);
} else if (action === 'POP') {
history.goBack();
} else if (action === 'REPLACE') {
history.replace(nextLocation);
}
props.closeStopRouteDialog(1);
setIsShowModal(false);
}
function onCancel() {
props.closeStopRouteDialog(0); //點擊取消和確定的事件
setIsShowModal(false);
}
return (
<>
{isShowModal && <Modal
title="是否返回?"
width='450'
visible={isShowModal}
confirm={()=>onConfirm()}
close={onCancel}
>
</Modal>}
</>
);
}
3.pushState popState
觸發機制:瀏覽器的返回和前進按鈕被點擊
缺點: 沒缺點了,js原生的
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin:0;
padding:0;
}
.menu{
width: 100px;
height: 40px;
font-size: 30px;
line-height: 40px;
text-align: center;
border:1px solid #000000;
float: left;
margin-left: 50px;
user-select: none;
}
p{
clear: both;
display: none;
}
.dialog{
width: 100%;
height: 100%;
background: black;
opacity: 0.5;
position: absolute;
top: 0;
left: 0;
display: none;
}
.container{
width: 500px;
height: 200px;
position: absolute;
z-index: 100;
left:calc(50% - 250px);
top:calc(50% - 100px);
background: #FFFFFF;
padding:24px;
display: flex;
flex-direction: column;
align-items: start;
justify-content: space-between;
}
.title{
color:#000000;
font-size: 30px;
line-height: 30px;
font-weight: 600;;
}
.btn{
}
.btnLeft{
width: 50px;
height: 30px;
background-color:red;
margin-right:395px;;
}
.btnRight{
width: 50px;
height: 30px;
background-color:chartreuse
}
</style>
</head>
<body>
<div class='menu'>水果</div>
<div class='menu'>蔬菜</div>
<div class='menu'>零食</div>
<div class='menu'>飲料</div>
<br>
<br>
<p>獼猴桃
蘋果
梨</p>
<p>白菜
土豆
地瓜</p>
<p>辣條
牛肉干
薯片</p>
<p>可樂
雪碧
果汁</p>
<div class='dialog'>
<div class='container'>
<div class='title'>確定要返回嗎</div>
<div class="btn">
<button class='btnLeft'>取消</button>
<button class='btnRight'>確定</button>
</div>
</div>
</div>
<script>
var arr,divs;
let dialog=document.querySelector('.dialog')
init()
function init(){
// 當歷史前進或者后退時就會收到這個事件
window.onpopstate=popStateHandler;
arr=Array.from(document.getElementsByTagName("p"));
divs=Array.from(document.querySelectorAll(".menu"));
cancel=document.querySelector('.btnLeft')
ensure=document.querySelector('.btnRight')
arr[0].style.display="block";
for(var i=0;i<divs.length;i++){
divs[i].onclick=clickHandler;
}
cancel.addEventListener('click',handleClick)
ensure.addEventListener('click',handleClick)
}
function clickHandler(){
var index=divs.indexOf(this);
// history.pushState({state:1},"","#"+this.innerHTML);
// 在歷史記錄列表中增加數據,后面的#內容標示當前跳轉部分
history.pushState({index:index}, "", document.URL);
changeMenu(index);
}
function popStateHandler(){
console.log(history.state);
// changeMenu(history.state.index)
dialog.style.display='block'
}
function changeMenu(index){
for(var i=0;i<arr.length;i++){
if(i===index){
arr[i].style.display="block";
}else{
arr[i].style.display="none";
}
}
}
function handleClick(e){
if(e.target.innerHTML==='確定'){
dialog.style.display='none'
console.log('點擊了確定')
location.href='http://www.baidu.com'
return ;
}
dialog.style.display='none'
console.log('點擊了取消')
// window.location.href='http://www.baidu.com'
}
</script>
</body>
</html>