一、背景:同事去學校作畢設請假,今天幫他修改h5bug 二、遇到的問題:移動端App打開某個網頁會自動彈出一個對話框,這個對話框出現的不合時宜,由於須要是在頁面作一些操做後點擊原生頂部的返回按鈕再彈出對話框 三、具體問題就是popstate形成的web
四、原來的代碼:api
window.addEventListener('popstate', function() { var btnArray = ['我要退出', '繼續計數']; mui.confirm('正在計數哦,肯定要退出嗎?', '提示', btnArray, function(e) { if(e.index == 1) { pushHistory(); } else { setBack(); } }) },false);
五、修改後的代碼:瀏覽器
window.addEventListener('load', function() { setTimeout(function() { window.addEventListener('popstate', function() { var btnArray = ['我要退出', '繼續計數']; mui.confirm('正在計數哦,肯定要退出嗎?', '提示', btnArray, function(e) { if(e.index == 1) { pushHistory(); } else { setBack(); } }) }); }, 0); });
六、暫且先解決問題,往後有時間繼續深刻研究session
研究一陣函數
七、說說過去ui
之前瀏覽器操做瀏覽器歷史記錄主要依據history對象。在它的_proto_繼承有back、forward、go等函數,那麼什麼是popState?簡而言之就是HTML5新增的用來控制瀏覽器歷史記錄的api。url
八、怎麼用?code
HTML5的新API擴展了window.history,使歷史記錄點更加開放了。能夠存儲當前歷史記錄點pushState、替換當前歷史記錄點replaceState、監聽歷史記錄點popstate。對象
history.pushState(data,title,url); //其中第一個參數data是給state的值;第二個參數title爲頁面的標題,但當前全部瀏覽器都忽略這個參數,傳個空字符串就好;第三個參數url是你想要去的連接;繼承
replaceState用法相似,例如:history.replaceState("首頁","",location.href+ "#web");
二者區別:pushState會改變history.length,而replaceState不改變history.length
九、有坑嗎?
popstate事件在webkit中的很詭異。popstate是HTML5的History系列中的事件,可是這玩意兒在webkit中的行爲至關讓人蛋疼。這回連IE10都站在了Firefox這邊,至少這邊的實用性強的多。雖然官方的文檔中對popstate的描述也沒有細節上的描述,不過以個人邏輯來判斷,這貨是就webkit的BUG。
Html5這套ApI和傳統的history不一樣,或者說這套API是「session history entries」。
注意注意:Html5種的HistoryAPI是不會使頁面跳轉的,只是操做地址欄和相應的state屬性而已,並且它是手動操做的。瀏覽器默認的History仍是傳統的那一套,雖然它們在瀏覽器上都使用同一個「歷史記錄堆棧」。
對這個差別的認知就是webkit中詭異行爲的緣由。webkit並無把HTML5的History和傳統的區分開,而根據官方文檔對popstate的描述,只要訪問歷史記錄就會觸發popstate。而傳統的History中訪問頁面和生產歷史記錄是同時的。因此在webkit中,不管是刷新仍是訪問一個新網頁都會觸發popstate。而其它瀏覽器中這個popstate僅做用於HTML5的History,並不響應傳統的History,更不用說刷新和訪問新網頁的狀況了。
緣由找到了,那麼解決方案呢?
一、對popstate延遲綁定的方法,由於popstate會在頁面加載完成以後不久觸發,因此在setTimeout一段時間後再綁定事件,popstate的第一次就不會輕易被webkit奪走了 二、判斷瀏覽器再作調整,直接針對webkit在頁面加載完成後第一次觸發的popstate屏蔽了