簡體   English   中英

如何在HTML5歷史狀態中存儲函數

[英]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並從數據對象中查找它。

這是我做的:

  • 每個HTML頁面都包含一個或多個可以創建新歷史記錄條目的組件。
  • 每個組件實現三種方法:
    1. getId()返回其唯一的DOM ID。
    2. getState()返回組件的狀態:

       { id: getId(), state: componentSpecificState } 
    3. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM