简体   繁体   English

如何在HTML5历史状态中存储函数

[英]How can I store functions within the HTML5 history states

So I'm using the HTML5 history management for adding the ability to navigate back and forward within a website with AJAX loaded subcontent. 因此,我使用HTML5历史记录管理来添加在具有AJAX加载的子内容的网站中前后导航的功能。

Now I would like to store javascript functions within the state object, to callback at the state popping. 现在我想在状态对象中存储javascript函数,以便在弹出状态下进行回调。 More or less like the following code: 或多或少像以下代码:

$(window).bind("popstate", function(event) {
    var state = event.originalEvent.state;
    if (!state) {
        return;
    }
    state.callback(state.argument);
}

function beforeLoad() {
    var resourceId = "xyz";
    var func;

    if (case1) {
        func = switchPageToMode1;
    } else { // case 2
        func = swithPageToMode2;
    }

    func(resourceId); // run the function
    window.history.pushState({ callback: func, resourceId: resourceId }, "newTitle", "newURL"); // and push it to history
}

function switchPageToMode1(resourceId) {
    alterPageLayoutSomeWay();
    loadResource(resourceId);
}

function swithPageToMode2(resourceId) {
    alterPageLayoutSomeOtherWay();
    loadResource(resourceId);
}

function loadResource(resourceId) {
    ...
}

All right. 好吧。 So what I'm trying to do is storing a reference to a javascript function. 所以我要做的是存储对javascript函数的引用。 But when pushing the state (the actual window.history.pushState call) the browser files a complaint, namely Error: "DATA_CLONE_ERR: DOM Exception 25" 但是当推送状态(实际的window.history.pushState调用)时,浏览器会提出投诉,即错误:“DATA_CLONE_ERR:DOM Exception 25”

Anybody knows what I'm doing wrong? 谁知道我做错了什么? Is it at all possible to store function calls within the state? 是否可以在州内存储函数调用?

No, it's not possible, not directly anyway. 不,这是不可能的,不是直接的。 According to MDC the "state object," ie the first argument to pushState , "can be anything that can be serialized." 根据MDC说法, “状态对象”,即pushState的第一个参数,“可以是任何可以序列化的东西”。 Unfortunately, you can't serialize a function. 不幸的是,你无法序列化一个函数。 The WHATWG spec says basically the same thing but in many more words, the gist of which is that functions are explicitly disallowed in the state object. WHATWG规范说的基本相同,但更多的话,其中的要点是在状态对象中明确禁止函数。

The solution would be to store either a string you can eval or the name of the function in the state object, eg: 解决方案是存储您可以eval的字符串或状态对象中的函数名称,例如:

$(window).bind("popstate", function(event) {
  var state = event.originalEvent.state;

  if ( !state ) { return; }

  window[ state.callback ]( state.argument );  // <-- look here
}

function beforeLoad() {
  var resourceId = "xyz",
      func
  ;

  if ( case1 ) {
    func = "switchPageToMode1";  // <-- string, not function
  } else {
    // case 2
    func = "swithPageToMode2";
  }

  window[ func ]( resourceId );  // <-- same here

  window.history.pushState(
    { callback : func,
      argument : resourceId
    },
    "newTitle", "newURL"
  );
}

Of course that's assuming switchPageToMode1 and -2 are in the global context (ie window ), which isn't the best practice. 当然,假设switchPageToMode1-2在全局上下文(即window )中,这不是最佳实践。 If not they'll have to be accessible somehow from the global context, eg [window.]MyAppGlobal.switchPageToMode1 , in which case you would call MyAppGlobal[ func ]( argument ) . 如果不是,则必须以某种方式从全局上下文访问它们,例如[window.]MyAppGlobal.switchPageToMode1 ,在这种情况下,您将调用MyAppGlobal[ func ]( argument )

I came up with a slightly different solution. 我提出了一个略有不同的解决方案。

I added two variables to the window variable 我在window变量中添加了两个变量

window.history.uniqueStateId = 0;
window.history.data = {}.

Each time I perform a pushstate, all I do is push a unique id for the first parameter 每次执行pushstate时,我所做的就是为第一个参数推送一个唯一的id

var data = { /* non-serializable data */ };
window.history.pushState({stateId : uniqueStateId}, '', url);
window.history.data[uniqueStateId] = data;

On the popstate event, I then just grab the id from the state object and look it up from the data object. 在popstate事件中,我只是从状态对象中获取id并从数据对象中查找它。

Here is what I do: 这是我做的:

  • Each HTML page contains one or more components that can create new History entries. 每个HTML页面都包含一个或多个可以创建新历史记录条目的组件。
  • Each component implements three methods: 每个组件实现三种方法:
    1. getId() which returns its unique DOM id. getId()返回其唯一的DOM ID。
    2. getState() that returns the component's state: getState()返回组件的状态:

       { id: getId(), state: componentSpecificState } 
    3. setState(state) that updates the component's state using the aforementioned value. setState(state)使用上述值更新组件的状态。
  • On page load, I initialize a mapping from component id to the component like so: 在页面加载时,我初始化从组件ID到组件的映射,如下所示:

     this.idToComponent[this.loginForm.getId()] = this.loginForm; this.idToComponent[this.signupForm.getId()] = this.signupForm; 
  • Components save their state before creating new History entries: history.replaceState(this.getState(), title, href); 组件在创建新的历史条目之前保存其状态: history.replaceState(this.getState(), title, href);

  • When the popstate event is fired I invoke: popstate事件被触发时,我调用:

     var component = this.idToComponent[history.state.id]; component.setState(history.state); 

To summarize: instead of serializing a function() we serialize the component id and fire its setState() function. 总结一下:我们不是序列化一个function()而是序列化组件id并setState()它的setState()函数。 This approach survives page loads. 这种方法可以在页面加载中存活

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何返回可用的历史状态数 - How can I return the number of history states available 如何在HTML页面中正确存储HTML模板? - How can I correctly store a HTML template within a HTML page? HTML5历史记录:如何查看弹出的URL(即单击“后退”按钮时所处的页面) - HTML5 history: how can I see the URL that was popped (ie, the page we were on when we hit the back button) 如何从HTML5 Windows应用商店应用中的代码关闭MessageDialog? - How can i close MessageDialog from code in HTML5 Windows Store app? 如何在HTML5的应用程序缓存中存储50MB的视频? - How can i store a 50MB video in HTML5's app cache? 在HTML5中,我可以直接从服务器将数据存储到“本地存储”吗? - In HTML5, can I store data to the 'localstorage' directly from server? 如何退回到HTML5 Canvas历史记录 - How to step back in HTML5 Canvas history 如何在HTML5 Canvas上下文中一个接一个地执行不同的动画 - How can I execute different animations one by one within a HTML5 Canvas context Ajax / HTML5历史状态(popState,pushState等)-后退按钮行为 - Ajax / HTML5 history states (popState, pushState, etc) - back button behavior 你可以使用HTML5本地存储来存储文件吗?如果没有,怎么样? - Can you use HTML5 local storage to store a file? If not, how?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM