移动端H5单页面应用路由变化与默认返回按钮效果不搭配解决方案

1,233 阅读4分钟

移动端H5单页面应用路由变化与默认返回按钮效果不搭配解决方案 #1

Open
beita1991 opened this Issue 28 days ago · 0 comments

Comments

Projects
None yet
1 participant
Owner

beita1991 commented 28 days ago edited

移动端H5单页面应用路由变化与默认返回按钮效果不搭配解决方案

功能与需求

做微信企业应用开发时,业务代码用的是react,路由用的react-router。遇到一种场景,列表页面(A)、选中项详情(B)、编辑功能(C)、选人功能(D),正常效果是 A-->B-->C-->D,然而D操作完后会跳转到B页面。用户点击左上角的微信应用自带返回按钮,这个时候返回到的是D页面,但是这个不是我想要的效果,我希望的是返回到A页面。

分析与提出问题

  • 如何知道浏览器返回操作呢?前进和后退等...
  • B页面到D页面如果是已知就两步的话可以用history.go(-2),但是当是未知步骤呢?

解决

从分析中可以看出应该与对应的 history Api 有关 ,查看相关 Api 与google了一番,发现了这遍blog 如何监听用户点击浏览器后退按钮
代吗如下:

        //监听hashchange事件
        window.addEventListener('hashchange', function() {

            //为当前导航页附加一个tag
            this.history.replaceState('hasHash', '', '');
            console.error('==============监听hashchange事件================')
        }, false);

        window.addEventListener('popstate', function(e) {
            if (e.state) {
                //侦测是用户触发的后退操作, dosomething
                //这里刷新当前url
                console.error('侦测是用户触发的后退操作',e.state)
            }
        }, false);

构建一个浏览历史存储对象,每次跳转将数据存储进去

 historyObject: {
     urlList: [],  // 浏览历史
     currentIndex: -1,
 }

这样可以知道浏览器的前进后退,然后将 对应的url与 urlList 中数据作比较,设置对应的index。
回到问题中用户D跳转到B,已知URL只要匹配 urlList 中数据然后找到对应的index,然后执行 history.go 去跳转。考虑到用户刷新操作,所以将数据变更存储到 localStorage 中
之后的工作就维护好这个 historyObject 对象。
丰富后的代码如下:

function urlFilter(url) {
    let index = url.indexOf('_k=');
    if (index > 0) {
        url = url.substring(0, index - 1);
    }
    return url;
}

let HistoryManager = {
    /**
     * 记录 history 列表
     * {
     *     urlList:[],   ['url_a','url_b']
     *     currentIndex: -1,
     * }
     */
    historyObject: {
        urlList: [],
        currentIndex: -1,
    },

    localStorageHistoryKey: 'HISTORY_MANAGER_LIST_KEY',

    // 初始化调用
    initialize() {
        // 初始化的时候判断localStory中是否有相关数据,如果有将其取出
        let historyObject = window.localStorage.getItem(this.localStorageHistoryKey);
        if (historyObject) {
            this.historyObject = JSON.parse(historyObject);
        }

        //监听hashchange事件
        window.addEventListener('hashchange', ()=>this.hashchangeEvent(), false);

        window.addEventListener('popstate', (e)=>this.popstateEvent(e), false);
    },

    hashchangeEvent(){
        window.history.replaceState('hasHash', '', '');
    },

    popstateEvent(e){
        if (e.state) {
            let url = urlFilter(window.location.href);

            let index = this.historyObject.urlList.findIndex((item, i) => item == url);

            this.setHistoryObject({
                currentIndex: index,
                urlList: this.historyObject.urlList,
            });

        }
    },

    removeEventListenter(){
        window.removeEventListener('hashchange',this.hashchangeEvent);
        window.removeEventListener('popstate',this.popstateEvent);

    },

    getHistoryObject(){
        return this.historyObject;
    },

    setHistoryObject(historyObject){
        this.historyObject = historyObject;
        if (window.localStorage.getItem(this.localStorageHistoryKey)) {
            window.localStorage.removeItem(this.localStorageHistoryKey);
        }
        window.localStorage.setItem(this.localStorageHistoryKey, JSON.stringify(this.historyObject));
        window.beitaTestHistory = this.historyObject;
    },

    compareUrl(newUrl, oldUrl){
        if (newUrl && oldUrl) {
            return newUrl === oldUrl;
        }
        throw {errorMessage: "HistoryManager.compareUrl 方法传入参数有误"};
        return false;
    },

    /**
     * 跳转 --这里只是存储数据,跳转是在调用当前方法时候用的 react-router 封装history对象 的 push方法
     */
    navTo(url){

        let {currentIndex, urlList}= this.historyObject;

        if (currentIndex > -1) {
            // 删除当前 currentIndex 后面的数据 再将 url添加进去
            if (currentIndex != (urlList.length - 1))
                urlList = urlList.splice(0,currentIndex+1);

            urlList.push(url);
            this.setHistoryObject({
                currentIndex: currentIndex + 1,
                urlList: urlList,
            })

        } else {
            throw {errorMessage: "未找到当前url"};
        }
    },

    popTo(url){
        url = urlFilter(url);
        let index = this.historyObject.urlList.findIndex((item, i) => item == url);
        this.go(index-this.historyObject.currentIndex);
    },

    /**
     * 替换 --这里只是存储数据,跳转是在调用当前方法时候用的 react-router 封装 history 对象 的 replace 方法
     */
    replaceTo(url){
        url = urlFilter(url);
        let {currentIndex, urlList}= this.historyObject;
        urlList[currentIndex]= url;
        this.setHistoryObject({
            currentIndex: currentIndex,
            urlList: urlList,
        })
    },

    getCurrentHistory(){
        return this.historyObject.urlList[this.historyObject.currentIndex] || undefined;
    },

    getCurrentHistoryIndex(){
        return this.historyObject.currentIndex;
    },

    back(){
        this.go(-1);
    },

    forward(){
        this.go(1);
    },

    go(n){
        window.history.go(n);
    },
};

module.exports = HistoryManager;

总结

  • history Api
  • 注意数据的存储
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can't perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.