53 lines
1.6 KiB
TypeScript
53 lines
1.6 KiB
TypeScript
import { useEffect } from 'react';
|
||||
|
|
import { FormInstance } from 'antd';
|
|||
|
|
|
|||
|
|
interface UseFormGuardOptions {
|
|||
|
|
form: FormInstance;
|
|||
|
|
enabled?: boolean;
|
|||
|
|
onSaveDraft?: () => void;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 表单离开拦截 Hook
|
|||
|
|
* - 浏览器刷新/关闭拦截 (beforeunload)
|
|||
|
|
* - 移动端切后台时保存草稿 (visibilitychange + pagehide)
|
|||
|
|
*
|
|||
|
|
* 注意:路由跳转拦截需要在使用组件中手动处理(因为 BrowserRouter 不支持 useBlocker)
|
|||
|
|
*/
|
|||
|
|
function useFormGuard(options: UseFormGuardOptions) {
|
|||
|
|
const { form, enabled = true, onSaveDraft } = options;
|
|||
|
|
|
|||
|
|
// 浏览器刷新/关闭拦截
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (!enabled) return;
|
|||
|
|
const handler = (e: BeforeUnloadEvent) => {
|
|||
|
|
if (form.isFieldsTouched()) {
|
|||
|
|
e.preventDefault();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
window.addEventListener('beforeunload', handler);
|
|||
|
|
return () => window.removeEventListener('beforeunload', handler);
|
|||
|
|
}, [form, enabled]);
|
|||
|
|
|
|||
|
|
// 移动端:页面切到后台时保存草稿
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (!enabled || !onSaveDraft) return;
|
|||
|
|
const handler = () => {
|
|||
|
|
if (document.visibilityState === 'hidden' && form.isFieldsTouched()) {
|
|||
|
|
onSaveDraft();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
document.addEventListener('visibilitychange', handler);
|
|||
|
|
const pageHideHandler = () => {
|
|||
|
|
if (form.isFieldsTouched()) onSaveDraft();
|
|||
|
|
};
|
|||
|
|
window.addEventListener('pagehide', pageHideHandler);
|
|||
|
|
return () => {
|
|||
|
|
document.removeEventListener('visibilitychange', handler);
|
|||
|
|
window.removeEventListener('pagehide', pageHideHandler);
|
|||
|
|
};
|
|||
|
|
}, [form, enabled, onSaveDraft]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default useFormGuard;
|