H5中安卓返回键拦截

1,276 阅读1分钟

需求描述:在h5页面中弹出提示框等模态框时,点击路由回退(安卓返回键等)未关闭模态框而是路由进行了回退,此方法在监测到回退操作时进行了一次拦截并抛出一个事件进行自定义操作

拦截方法封装:

export function popstateListener(callback: Function) {
    history.pushState(null, "", location.href);
    let popstateFun = () => {
        callback();
        window.removeEventListener("popstate", popstateFun);
    }
    window.addEventListener("popstate", popstateFun);
}

使用方法:

popstateListener(() => {
     console.log("已拦截返回事件,执行自己的操作")
})

改进方法:

// 该方法当前页不是第一视图时(包含子路由已显示)务必移除,否则有未知错误
let callbacks;
let hasListenersBack = false;
let listenersBackIdentifier;
function popstateFun() {
    callbacks();
    window.removeEventListener("popstate", popstateFun);
    hasListenersBack = false;
    listenersBackIdentifier = null;
}
class PopstateHandler {
    // 页面中有多处需要注册时加上identifier区分
    popstateListener(callback: Function, identifier?: string) {
        if (!hasListenersBack) {
            hasListenersBack = true;
            callbacks = callback;
            listenersBackIdentifier = identifier;
            history.pushState(null, "", location.href);
            window.addEventListener("popstate", popstateFun);
        }
    }
    removePopstateListener(identifier?: string) {
        // 监听时未添加标识或者与监听时添加标识一样可移除
        setTimeout(() => {
            if ((listenersBackIdentifier && listenersBackIdentifier === identifier) || !identifier) {
                window.removeEventListener("popstate", popstateFun);
                hasListenersBack = false;
                listenersBackIdentifier = null;
                history.back()
            }
        });
    }
}
export const popstateHandler = new PopstateHandler();

防止监听方法重复注册,同时添加identifier标识,只有上次注册的identifier被清除后才能再次注册,防止页面中多处需要拦截造成混乱