单页面返回上一页,如何保持数据?

先讲一下背景:用户从列表页进入详情页,然后用户返回列表页,列表页需要停留在上次离开时的页面状态(页面滚动高度、搜索条件等等)。

最近在做车问项目,用户需要频繁往返列表页和详情页,为了提升用户体验,我将页面系统改成了单页面。虽然性能提升上去了,但是产品经理反馈列表页面体验并不好,需要解决页面返回保持页面状态。

以前做项目,大部分都是页面直接<a href="xxx"/>跳转,这时候浏览器会将上一个页面的状态保存起来,用户返回的时候就会自动恢复。现在单页面需要模拟回这个功能,于是就有了下面的思路。

思路

用户即将离开页面 -> 保存Vue.$data和当前页面滚动高度到sessionStorage

用户从详情页返回列表页 -> 从sessionStorage读取之前保存的数据 -> 页面重新设置

代码

/**
 * 页面状态持久化
 * 
 * @author 张子超
 * @since 2018-08-16
 */
import $ from "jquery";

var PageState = {};

var defaultUIData = ()=>{
    return {
        scrollTop: $(window).scrollTop()
    };
}

/**
 * 启动监听,当Component.keepAlive = true时启用
 * @param {*} $root App对象
 */
PageState.start = function($root){
    var timer;

    window.addEventListener("scroll",()=>{
      //延时保存
      clearTimeout(timer);
      timer = setTimeout(()=>{
        //获取当前的组件
        var component = $root.$route.matched["0"].components.default;
        if(component.keepAlive){
            //保存当前组件的数据
            PageState.save($root.$root.$children["0"].$children["0"]);
        }
      }, 300);
    });
}

/**
 * 保存当前组件的数据
 * @param {*} vueObj 
 */
PageState.save = function(vueObj){
    var key = 'PS:'+location.pathname+location.search;
    var state = {
        //页面数据
        PageData: vueObj.$data,
        //UI数据
        UIData: defaultUIData()
    };
    try{
        sessionStorage.setItem(key, JSON.stringify(state));
    }catch(e){
        console.error(e);
    }
}

PageState.recover = function(vueObj, initCb = ()=>{}, recoverCb = ()=>{}){
    var key = 'PS:'+location.pathname+location.search;
    try{
        var dataStr = sessionStorage.getItem(key);

        if(!dataStr){
            console.log('无法获取恢复数据');
            initCb();
            return;
        }
        console.log('恢复数据');
        var state = JSON.parse(dataStr);
        console.log(state);
        for(var i in state.PageData){
            console.log('恢复:'+i+'='+state.PageData[i]);
            vueObj[i] = state.PageData[i];
        }

        var scrollTop = state.UIData.scrollTop;
        if(scrollTop){

            setTimeout(()=>{
                console.log('滚动:'+scrollTop);
                $(window).scrollTop(scrollTop);
            }, 10);

        }
        //清除状态
        PageState.clear();
        //回调恢复完成
        recoverCb();
    }catch(e){
        console.error(e);
        //回调恢复完成
        initCb();
    }
}

PageState.clear = function(){
    sessionStorage.clear();
}

export default PageState;