如何使用Javascript保存和恢复整个网站?

时间:2011-04-22 10:59:44

标签: javascript html javascript-events

您好我正在使用Javascript开发自己的路由器API。它基于#FregmentIdentifiers(document.location.hash)进行路由。

api完成了almos,但我仍然在做backbuttom活动。每当按下后退按钮并且哈希值发生变化时,之前就会看到,旧内容将被恢复。

您知道如何保存和恢复所有内容吗?

我的问题是,如果我保存并恢复document.body.innerHTML,只会恢复标记,但不会恢复事件,例如googlemaps停止工作。 我试图克隆document.body或document.documentElement,但javascript或者告诉我该字段没有setter或者我的克隆无效。

编辑:

为了明确我正在做的事情,我决定发布我当前的代码。 问题针对标有// TODO评论的部分。

function Router(){
var that = this;
var router = this;
var executionObservers = [];
that.routes = [];
this.registerRoute = function(route){
    that.routes.push(route);
};
var history = null;
this.init = function(){
    var i;
    var identifier = document.location.hash;
    history = new History();
    history.start();
    if(identifier.length > 0){
        identifier = identifier.substring(1,identifier.length);
        for(i = 0; i< that.routes.length; i++){
            var route = that.routes[i];
            if(route.contains(identifier)){
                route.getAction(identifier)(route.getParams(identifier));
                return true;
            }
        }
    }
    return false;
};
this.executed = function (identifier){
    var i; 
    for(i=0; i<executionObservers.length; i++){
        executionObservers[i](identifier);
    }
    document.location.hash = identifier;
};

this.addExecutionObserver = function(observer){
    executionObservers.push(observer);
};

function History(){
    var history = [];
    var timeout = 200;
    var lastAddedHash = null;
    var loop = function(callback){
        var hash = window.location.hash;
        window.setTimeout(
            function(){
                if(window.location.hash!=hash){
                    hash = window.location.hash;
                    callback(hash);
                }
                loop(callback);
            },
            timeout
        );
    };
    this.add = function(hash){
        lastAddedHash  = hash;
        window.setTimeout(addCallback(hash), timeout);          
    };
    addCallback = function(hash){
        return function(){
            var i;
            var found = false;
            for(i =0; i< history.length&&!found; i++){
                if(history[i][1] == hash){
                    found = true;
                    //TODO create backup
                    //history[i][0] = 
                }
            }
            if(!found){history.push(new Array(document.documentElement.cloneNode(true),hash));}
        }
    }
    this.setTimeout = function(micoseconds){
        timeout = microseconds;
    };
    started = false;
    this.start = function(){
        if(!started){
            started = true;
            loop(function(hash){
                var i;
                if(lastAddedHash!=null&&hash!=lastAddedHash){
                    for(i =0; i<history.length; i++){
                        if(history[i][1] == hash){
                            //TODO restore from backup
                            document.location.reload();
                        }
                    }
                }
            });
        }
    };
    router.addExecutionObserver(this.add);
}
}

Router.instance = null;
Router.getInstance = function(){
    if(Router.instance === null ){
        Router.instance = new Router();
    }
    return Router.instance;
};

/**
 * @param getParams = function(identifier)
 * @param getIdentifier = function(params)
 * @param contains = function(identifier)
 */
function Route(action, getParams, getIdentifier, contains){
    var that = this;
    var router = Router.getInstance();
    this.contains = contains;
    this.getParams = getParams;
    this.getAction = function(){
        return action;
    }
    this.reExecute = function(identifier){
        action(getParams(identifier));
    };
    this.execute = function(params){
        action(params);
        this.executed(params);
    }
    this.executed = function(params){
        router.executed('#' + getIdentifier(params));
    };
    this.register = function(){
        router.registerRoute(this);
    };
}
function PrefixedRouterConfig(prefix,paramRegexes){
    this.contains = function(identifier){
        var regex = "^" + prefix;
        for(var i=0;i<paramRegexes.length;i++){
            regex+="_"+paramRegexes[i];
        }
        regex +="$";
        var match = identifier.match(regex);
        return match != null && (typeof match) == 'object' && (match[0] == identifier);
    };
    this.getIdentifier = function(params){
        ret = prefix;
        for(var i=0;i<params.length;i++){
            ret+="_"+params[i];
        }
        return ret;
    };
    this.getParams = function(identifier){
        var regex = "^" + prefix;
        for(var i=0;i<paramRegexes.length;i++){
            regex+="_("+paramRegexes[i]+")";
        }
        regex +="$";
        var matches = identifier.match(regex);
        var ret = [];
        for(var i=1;i<matches.length;i++){
            ret.push(matches[i]);
        }
        return ret;
    };
}

我的api的示例用法可能如下所示:

config = new PrefixedRouterConfig('show_map',new Array("\\d+", "-?\\d+(?:\\.\\d+)?", "-?\\d+(?:\\.\\d+)?"));
var ROUTE_SHOW_MAP = new Route(
    function(params){
        var zoom = params[0];
        var lat = params[1];
        var lng = params[2];
        MyGmapInterface.preparePage(-1);
        addTabSelectedCallback(MyGmapInterface.tabLoaded);
        addTabClosedCallback(MyGmapInterface.tabClosed);
        MyGmapInterface.tabsLoaded = true;
        MyGmapInterface.myMap = new MyMap(lat,lng,zoom,MyGmapInterface.getMapContainer(),MyGmapInterface.notCompatible);
        MyGmapInterface.addNewCamMarkers(MyGmapInterface.loadCams());
        MyGmapInterface.initListeners();
        tabSelected(TAB_LEFT);
    },
    config.getParams,
    config.getIdentifier,
    config.contains
);
ROUTE_SHOW_MAP.register();

包含所有Javascript文件(可能注册路由)后,我调用Router.getInstance()。init();

当我在某处做一个存在路径的ajax请求(手动)时,我调用ROUTE_NAME.executed()来设置fregment标识符并将其注册到历史记录中。

此外,我有一个观察者,只要执行()

更改位置哈希,就会更新一些用于直接翻译的链接。

6 个答案:

答案 0 :(得分:8)

这与刷新的情况相同,因此您应该重新使用该系统。

基本上,您的哈希必须包含足够的信息来重建整个页面。当然,有时您需要保存一些用户输入来重建页面。这就是localStorage的用途(IE的userData)

答案 1 :(得分:2)

除非你通过跟踪它们的API添加了你的事件(比如jQuery;请参阅http://api.jquery.com/clone#true),否则你将无法反思为了使它们序列化而添加的事件/保留。

如果您不太可能选择使用DOM用户数据,那么您还需要setUserData()来序列化任何DOM用户数据(或者再次,像jQuery这样的库来跟踪它)。

答案 2 :(得分:2)

如何在IFRAME中拥有所有内容并镜像父级中的所有URL片段更改,然后对iframe执行操作。这可能是跨站点脚本问题。

你正在做的事情非常困难,因为浏览器缓存 - 它决定是否从内存加载 - 而不是你。因此,如果上述选项不是一个选项,那么您创建此选项的唯一方法是通过浏览器扩展来监听选项卡后退按钮事件并采取相应措施。

答案 3 :(得分:1)

你看过jQuery history plugin了吗?我知道在另一篇文章中你提到jQuery不是一个选项,但你可能会模仿他们的方法。

我不是这方面的专家,但由于不同的浏览器实现,我相信这不是一件容易的来实现跨浏览器的工作。

主要网站:http://tkyk.github.com/jquery-history-plugin/#

演示页:http://www.serpere.info/jquery-history-plugin/samples/ajax/

答案 4 :(得分:1)

你想要的几乎是不可能的,你可以这样做,如果你使用像jquery这样的库来构建你的页面事件,如brettz9建议,但在你的情况下你使用谷歌地图和其他外部库,所以它不是一个选项。 这里的方法是知道你在哪个页面,并执行初始化该页面的javascript,就好像它是第一次加载页面一样。为此,您不仅需要跟踪页面的html,还要跟踪页面加载时执行的javascripts。

答案 5 :(得分:0)

我知道的唯一方法是欺骗浏览器,使其相信每个有价值的事件都是新页面。您可以通过使用window.location加载新页面来执行此操作,或使用get(=查询字符串)提交表单。新位置或表单数据必须包含显示正确信息所需的所有内容。这有其缺点 - 这是我的观点:

好:

  • 后退和前进按钮正常工作
  • 您的数据视图可以加入书签
  • 小心使用查询字符串数据,它为您的系统提供API

为:

  • 每个有价值的活动都必须通过页面上传
  • 无法利用ajax
  • 您必须设计一种以查询字符串形式对系统的每个状态进行编码的方法。