[英]How can I store functions within the HTML5 history states
因此,我使用HTML5歷史記錄管理來添加在具有AJAX加載的子內容的網站中前后導航的功能。
現在我想在狀態對象中存儲javascript函數,以便在彈出狀態下進行回調。 或多或少像以下代碼:
$(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) {
...
}
好吧。 所以我要做的是存儲對javascript函數的引用。 但是當推送狀態(實際的window.history.pushState調用)時,瀏覽器會提出投訴,即錯誤:“DATA_CLONE_ERR:DOM Exception 25”
誰知道我做錯了什么? 是否可以在州內存儲函數調用?
不,這是不可能的,不是直接的。 根據MDC的說法, “狀態對象”,即pushState
的第一個參數,“可以是任何可以序列化的東西”。 不幸的是,你無法序列化一個函數。 WHATWG規范說的基本相同,但更多的話,其中的要點是在狀態對象中明確禁止函數。
解決方案是存儲您可以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"
);
}
當然,假設switchPageToMode1
和-2
在全局上下文(即window
)中,這不是最佳實踐。 如果不是,則必須以某種方式從全局上下文訪問它們,例如[window.]MyAppGlobal.switchPageToMode1
,在這種情況下,您將調用MyAppGlobal[ func ]( argument )
。
我提出了一個略有不同的解決方案。
我在window變量中添加了兩個變量
window.history.uniqueStateId = 0;
window.history.data = {}.
每次執行pushstate時,我所做的就是為第一個參數推送一個唯一的id
var data = { /* non-serializable data */ };
window.history.pushState({stateId : uniqueStateId}, '', url);
window.history.data[uniqueStateId] = data;
在popstate事件中,我只是從狀態對象中獲取id並從數據對象中查找它。
這是我做的:
getId()
返回其唯一的DOM ID。 getState()
返回組件的狀態: { id: getId(), state: componentSpecificState }
setState(state)
使用上述值更新組件的狀態。 在頁面加載時,我初始化從組件ID到組件的映射,如下所示:
this.idToComponent[this.loginForm.getId()] = this.loginForm; this.idToComponent[this.signupForm.getId()] = this.signupForm;
組件在創建新的歷史條目之前保存其狀態: history.replaceState(this.getState(), title, href);
當popstate
事件被觸發時,我調用:
var component = this.idToComponent[history.state.id]; component.setState(history.state);
總結一下:我們不是序列化一個function()
而是序列化組件id並setState()
它的setState()
函數。 這種方法可以在頁面加載中存活
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.