ie8中支持onhashchange事件,在ie6中不支持,ie6使用一个iframe的open,将token记录在iframe中实现的。
以下是js版本:
<iframe src="javascript:''" id='__gwt_historyFrame' style='position: absolute; width: 0; height: 0; border: 0'></iframe> <a href="javascript:myhistory.newItem('a')">a</a> <a href="javascript:myhistory.newItem('b')">b</a> <script> var myhistory={ historyFrame:null, callback:[], addCallback:function(callback){ myhistory.callback[myhistory.callback.length] = callback; }, init:function (){ myhistory.historyFrame = document.getElementById('__gwt_historyFrame'); var token = ''; // Get the initial token from the url's hash component. var href = window.location.href; var hashLoc = href.lastIndexOf("#"); var token= (hashLoc > 0) ? href.substring(hashLoc+1) : ""; myhistory.setToken(token); var tokenElement; if (myhistory.historyFrame.contentWindow) { var doc = myhistory.historyFrame.contentWindow.document; tokenElement = doc.getElementById('__gwt_historyToken'); } if(tokenElement){ myhistory.setToken(tokenElement.innerText); }else{ myhistory.navigateFrame(token); } }, __gwt_onHistoryLoad : function(token) { if(token){ var hash = myhistory.encodeFragment(token); window.location.hash=hash; myhistory.newItemOnEvent(token); } }, newItemOnEvent:function(token){ for(var i = 0 ; i<myhistory.callback.length;i++){ var call = myhistory.callback[i]; call(token); } }, decodeFragment:function(fragment){ // decodeURI() does *not* decode the '#' character. return decodeURI(fragment.replace("%23", "#")); }, encodeFragment:function(fragment){ // encodeURI() does *not* encode the '#' character. return encodeURI(fragment).replace("#", "%23"); }, setToken:function(token){ window.__gwt_historyToken = token; }, getToken:function(){ return window.__gwt_historyToken; }, newItem:function(historyToken){ var historyToken = (historyToken == null) ? "" : historyToken; if (historyToken!=(myhistory.getToken())) { myhistory.setToken(historyToken); myhistory.nativeUpdate(historyToken); //if (issueEvent) { // fireHistoryChangedImpl(historyToken); //} } }, navigateFrame:function(token){ var div = document.createElement('div'); div.innerText=token; var escaped = div.innerHTML; var doc = myhistory.historyFrame.contentWindow.document; doc.open(); doc.write('<html><body onload="if(parent.myhistory.__gwt_onHistoryLoad)parent.myhistory.__gwt_onHistoryLoad(__gwt_historyToken.innerText)"><div id="__gwt_historyToken">' + escaped + '</div></body></html>'); doc.close(); }, nativeUpdate:function(token){ var hash = myhistory.encodeFragment(token); window.location.hash=hash; myhistory.navigateFrame(token); } } myhistory.addCallback(function mycall(token){ alert("hahah="+token);}); myhistory.init(); </script>
gwt实现history前进后退的代码:
http://code.google.com/p/google-web-toolkit/source/browse/trunk/user/src/com/google/gwt/user/client/impl/HistoryImpl.java?r=5606
/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.user.client.impl; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT.UncaughtExceptionHandler; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.HasHandlers; /** * Native implementation associated with * {@link com.google.gwt.user.client.History}. * User classes should not use this class directly. * * <p> * This base version uses the HTML5 standard window.onhashchange event to * determine when the URL hash identifier changes. * </p> */ public class HistoryImpl implements HasValueChangeHandlers<String>, HasHandlers { static boolean updateHashOnIE6 = true; /** * Sets whether the IE6 history implementation will update the URL hash when * creating a new item. This should be used only for applications with large * DOM structures that are suffering from performance problems when creating * a new history item on IE6 and 7. */ public static void setUpdateHashOnIE6(boolean updateHash) { HistoryImpl.updateHashOnIE6 = updateHash; } public static native String getToken() /*-{ return $wnd.__gwt_historyToken || ""; }-*/; protected static native void setToken(String token) /*-{ $wnd.__gwt_historyToken = token; }-*/; private HandlerManager handlers = new HandlerManager(null); /** * Adds a {@link ValueChangeEvent} handler to be informed of changes to the * browser's history stack. * * @param handler the handler */ public HandlerRegistration addValueChangeHandler( ValueChangeHandler<String> handler) { return handlers.addHandler(ValueChangeEvent.getType(), handler); } public void fireEvent(GwtEvent<?> event) { handlers.fireEvent(event); } /** * Fires the {@link ValueChangeEvent} to all handlers with the given tokens. */ public void fireHistoryChangedImpl(String newToken) { ValueChangeEvent.fire(this, newToken); } public HandlerManager getHandlers() { return handlers; } public native boolean init() /*-{ var token = ''; // Get the initial token from the url's hash component. var hash = $wnd.location.hash; if (hash.length > 0) { token = [email protected]::decodeFragment(Ljava/lang/String;)(hash.substring(1)); } @com.google.gwt.user.client.impl.HistoryImpl::setToken(Ljava/lang/String;)(token); var historyImpl = this; $wnd.onhashchange = function() { var token = '', hash = $wnd.location.hash; if (hash.length > 0) { token = [email protected]::decodeFragment(Ljava/lang/String;)(hash.substring(1)); } [email protected]::newItemOnEvent(Ljava/lang/String;)(token); }; return true; }-*/; public final void newItem(String historyToken, boolean issueEvent) { historyToken = (historyToken == null) ? "" : historyToken; if (!historyToken.equals(getToken())) { setToken(historyToken); nativeUpdate(historyToken); if (issueEvent) { fireHistoryChangedImpl(historyToken); } } } public final void newItemOnEvent(String historyToken) { historyToken = (historyToken == null) ? "" : historyToken; if (!historyToken.equals(getToken())) { setToken(historyToken); nativeUpdateOnEvent(historyToken); fireHistoryChanged(historyToken); } } protected native String decodeFragment(String encodedFragment) /*-{ // decodeURI() does *not* decode the '#' character. return decodeURI(encodedFragment.replace("%23", "#")); }-*/; protected native String encodeFragment(String fragment) /*-{ // encodeURI() does *not* encode the '#' character. return encodeURI(fragment).replace("#", "%23"); }-*/; /** * The standard updateHash implementation assigns to location.hash() with an * encoded history token. */ protected native void nativeUpdate(String historyToken) /*-{ $wnd.location.hash = [email protected]::encodeFragment(Ljava/lang/String;)(historyToken); }-*/; protected void nativeUpdateOnEvent(String historyToken) { // Do nothing, the hash is already updated. } private void fireHistoryChanged(String newToken) { UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler(); if (handler != null) { fireHistoryChangedAndCatch(newToken, handler); } else { fireHistoryChangedImpl(newToken); } } private void fireHistoryChangedAndCatch(String newToken, UncaughtExceptionHandler handler) { try { fireHistoryChangedImpl(newToken); } catch (Throwable e) { handler.onUncaughtException(e); } } }