[英]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: 这是我做的:
getId()
which returns its unique DOM id. getId()
返回其唯一的DOM ID。 getState()
that returns the component's state: getState()
返回组件的状态: { id: getId(), state: componentSpecificState }
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.