H5页面监听Android物理返回键

Android物理返回键的点击事件,通常webview的默认行为是 window.history.go(-1) ,可是在实际需求场景下,简单的页面回退并不能知足需求,因此须要H5页面监听Android物理返回键从而自定义处理方法。react

本方案的代码都在 h5_android_back 仓库中android

原理

主要是运用 HTML5 History API 实现。因此,首先简单介绍下 HTML5 History APIgit

HTML5 History API

history 属性

history.length

history.state
复制代码

history 方法

history.back()

history.forward()

history.go()
复制代码

HTML5 新API

history.pushState(state, title, url); 添加一条历史记录,不刷新页面
history.replaceState(state, title, url); 替换一条历史记录,不刷新页面

事件

popState事件:历史记录发生变化时触发,调用history.pushState()history.replaceState()不会触发此事件
window.addEventListener('popstate', handlePopstate);
复制代码
hashchange事件:页面hash值发生改变时触发
window.addEventListener('hashchange', handleHashChange);
复制代码

监听Android物理返回键实现

// index.js
(function (pkg) {
    var STATE = '_android_back';
    // 维护处理方法的栈
    var _android_back_handles = [];
    // 触发一次popstate方法,则调用最新处理方法
    var handlePopstate = function () {
        var handle = _android_back_handles.pop();
        handle && handle();
    };
    // 经过调用listen方法添加处理方法
    var listen = function (handle) {
        _android_back_handles.push(handle);
    };
    // 经过调用push方法,新增一条历史记录,并添加对应处理方法
    var push = function (state, handle) {
        if (handle) {
            history.pushState(state, null, location.href);
            handle && _android_back_handles.push(handle);
        }
    };
    const init = function () {
        // 经过调用 history.pushState() 方法添加一条历史记录
        history.pushState(STATE, null, location.href);
        // 监听 popstate 事件,当点击Android物理返回键时,会触发该事件
        window.addEventListener('popstate', handlePopstate);
        this.listen = listen;
        this.push = push;
    };

    init.call(window[pkg] = window[pkg] || {});
})('AndroidBack');
复制代码

此实现参考了 github.com/iazrael/xba… ,在此基础上,根据须要修改和添加了一部分代码github

此外,封装了一个React高阶组件,方便React项目使用,代码以下:web

import * as React from 'react';

export default (Target, handleBack) => {
    return class AndroidBack extends React.Component {
        _handles = []
        back = () => {
            window.history.go(-1);
        }
        componentDidMount () {
            // 经过调用 history.pushState() 方法添加一条历史记录
            history.pushState('_android_back', null, location.href);
            // 监听 popstate 事件,当点击Android物理返回键时,会触发该事件
            window.addEventListener('popstate', this.handlePopstate);
            if (handleBack) {
                // 添加自定义处理方法
                this._handles.push(handleBack);
            } else {
                // 若是没有自定义处理方法,默认调用 window.history.go(-1);
                this._handles.push(this.back);
            }
        }
        componentWillUnmount () {
            window.removeEventListener('popstate', this.handlePopstate);
        }
        // 触发一次popstate方法,则调用最新处理方法
        handlePopstate = () => {
            const handle = this._handles.pop();
            handle && handle();
        }
        // 经过调用push方法,新增一条历史记录,并添加对应处理方法
        push = (state, handle) => {
            if (handle) {
                history.pushState(state, null, location.href);
                this._handles.push(handle);
            }
        }
        render () {
            return (
                <Target {...this.props} _android_back_push={this.push}/> ); } }; }; 复制代码

实现原理基本在注释中注明,在这就不详细叙述了,全部代码在 h5_android_back 仓库中浏览器

使用

两种方式:ui

一、将对象挂在window上,支持任意页面接入,使用以下:this

index.jsurl

// 监听Android物理返回键,自定义处理方法
window.AndroidBack.listen(() => {
    console.log('back');
});
// 新增Android物理返回键监听事件,使用场景,好比:页面内弹出浮层,点击Android物理返回键,不是回退页面,而是关闭浮层
window.AndroidBack.push('close_modal', () => {
    // 关闭弹窗
    console.log('close_modal');
});
复制代码

二、封装了React高阶组件,支持React项目接入,使用以下:spa

index_react.js

import * as React from 'react';
import AndroidBack from 'h5_android_back/index_react.js';

class App extends React.Component {
    // ...
    openModal = () => {
        // 新增Android物理返回键监听事件,使用场景,好比:页面内弹出浮层,点击Android物理返回键,不是回退页面,而是关闭浮层
        this.props._android_back_push('close_modal', () => {
            // 关闭弹窗
            console.log('close_modal');
        });
    }
}

// 监听Android物理返回键,自定义处理方法
export default AndroidBack(App, () => {
    console.log('back');
})
复制代码

写在最后

注:此方案使用于全部浏览器及默认行为是页面回退的webview

此方案在我平时工做中使用正常,但愿能对有须要的小伙伴有帮助~~~

喜欢个人文章小伙伴能够去 个人我的博客 点star ⭐️

相关文章
相关标签/搜索