3

Ext.History ユーティリティ (バージョン 3.4.0) が IE8+ で正常に動作することに問題があります。Quirks モードでは機能しますが、IE8 標準モード (IE8) または IE9 標準モード (IE9) のドキュメント モードでは機能しません。CSS が適切にレンダリングされていないため、Quirks モードが機能していません。

history ユーティリティ以外のすべてをアプリから取り除き、(extjs ファイル以外に) 2 つのファイルを作成しました。

index.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>

<head>
        <script type="text/javascript" src="ext-base.js"></script>
        <script type="text/javascript" src="ext-all.js"></script>
        <script type="text/javascript" src="myapp.js"></script>
</head>

<body>

<div>
    <div align="center">
        <table width="97%" border="0" cellpadding="0" cellspacing="0" >
            <tr>
                <td>
                    <a href="#link1">Link1</a> |
                    <a href="#link2">Link2</a> |
                    <a href="#link3">Link3</a> |
                    <a href="#link4">Link4</a> |
                    <a href="#link5">link5</a>
                </td>
            </tr>
        </table>
    </div>
</div>

<!-- Fields required for history management -->
<form id="history-form" class="x-hidden">
    <input type="hidden" id="x-history-field"/>
    <iframe id="x-history-frame"></iframe>
</form>

</body>
</html>

myapp.js:

Ext.ns('MyApp');

Ext.onReady(function()
{
Ext.History.init();
    Ext.History.on('change', function(token){}, this);
});

アプリを Web サーバーにロードし、index.html に移動して link1 をクリックすると、アドレス バーに #link1 と表示されます。次に link2 をクリックすると、アドレス バーに #link2 が表示されます。次に link3 をクリックすると、アドレス バーに #link3 と表示されます。

IE7 エミュレーションを使用する IE、Chrome または Firefox で戻るボタンを使用すると、アドレス バーは #link3 から #link2 に移動します。もう一度戻るボタンを押すと、アドレス バーが #link2 から #link1 に移動します。これは私が期待する動作です。

ただし、適切なドキュメント標準モードで IE8 または IE 9 を使用している場合、[戻る] ボタンをもう一度クリックすると、アドレス バーが #link2 から #link3 に戻ります。戻るボタンをさらにクリックすると、#link2 と #link3 の間でユーザーが切り替わるだけです。これは予期しない動作であり、アプリケーションが正常に動作しない原因となっています。

これは、Sencha の例が 3.4.0 で機能する方法であることに注意してください。

Sencha 3.4 サンプル

(ページは Quirks モードで表示されますが、IE8 標準または IE9 標準に変更すると機能しません)。

4.1 で適切に動作しているように見えます。

(リンクを2つだけ投稿させてください。しかし、おそらく見つけることができます...)

私は Ext 3.4.1 にアクセスできませんが、この問題はバグ修正としてリストされていません。doctype の変更が機能することを示唆する1 つのスレッド ( here ) を見たことがありますが、そうではないようです (すべての doctype を試しました...)。

アプリの多くの部分でナビゲーションに History ユーティリティが使用されているため、これを削除することは受け入れられる解決策ではないことに注意してください。

どうすればこれを機能させることができるかについて、誰かが提案できますか?

4

2 に答える 2

1

これが私がそれを解決した方法です:

新しいパッチ JavaScript ファイルを作成し、ext ファイルの後に含めました

/*
 @Author: RWR 20130224

 This fixes the issue with backward traversal of history in IE8 & higher in standard document mode.

 This class was challenging to override (http://www.sencha.com/forum/showthread.php?46306-Help-How-to-extend-Ext.History)
 I ended up pasting all of the source original code here and making the necessary changes.

 NOTE that this may be patched in version 3.4.1.  It is definitely patched in 4.1.  When upgrading, validate that this patch is still required.
 */
NewHistory = (function () {
var iframe, hiddenField;
var ready = false;
var currentToken;
var oldIEMode = Ext.isIE6 || Ext.isIE7 || !Ext.isStrict && Ext.isIE8;

function getHash() {
    var href = location.href, i = href.indexOf("#"),
        hash = i >= 0 ? href.substr(i + 1) : null;

    if (Ext.isGecko) {
        hash = decodeURIComponent(hash);
    }
    return hash;
}

function doSave() {
    hiddenField.value = currentToken;
}

function handleStateChange(token) {
    currentToken = token;
    Ext.History.fireEvent('change', token);
}

function updateIFrame (token) {
    var html = ['<html><body><div id="state">',Ext.util.Format.htmlEncode(token),'</div></body></html>'].join('');
    try {
        var doc = iframe.contentWindow.document;
        doc.open();
        doc.write(html);
        doc.close();
        return true;
    } catch (e) {
        return false;
    }
}

function checkIFrame() {
    if (!iframe.contentWindow || !iframe.contentWindow.document) {
        setTimeout(checkIFrame, 10);
        return;
    }

    var doc = iframe.contentWindow.document;
    var elem = doc.getElementById("state");
    var token = elem ? elem.innerText : null;

    var hash = getHash();

    setInterval(function () {

        doc = iframe.contentWindow.document;
        elem = doc.getElementById("state");

        var newtoken = elem ? elem.innerText : null;

        var newHash = getHash();

        if (newtoken !== token) {
            token = newtoken;
            handleStateChange(token);
            location.hash = token;
            hash = token;
            doSave();
        } else if (newHash !== hash) {
            hash = newHash;
            updateIFrame(newHash);
        }

    }, 50);

    ready = true;

    Ext.History.fireEvent('ready', Ext.History);
}

function startUp() {
    currentToken = hiddenField.value ? hiddenField.value : getHash();

    if (oldIEMode) {
        checkIFrame();
    } else {
        var hash = getHash();
        setInterval(function () {
            var newHash = getHash();
            if (newHash !== hash) {
                hash = newHash;
                handleStateChange(hash);
                doSave();
            }
        }, 50);
        ready = true;
        Ext.History.fireEvent('ready', Ext.History);
    }
}

return {
    /**
     * The id of the hidden field required for storing the current history token.
     * @type String
     * @property s
     */
    fieldId: 'x-history-field',
    /**
     * The id of the iframe required by IE to manage the history stack.
     * @type String
     * @property s
     */
    iframeId: 'x-history-frame',

    events:{},

    /**
     * Initialize the global History instance.
     * @param {Boolean} onReady (optional) A callback function that will be called once the history
     * component is fully initialized.
     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser window.
     */
    init: function (onReady, scope) {
        if(ready) {
            Ext.callback(onReady, scope, [this]);
            return;
        }
        if(!Ext.isReady){
            Ext.onReady(function(){
                Ext.History.init(onReady, scope);
            });
            return;
        }
        hiddenField = Ext.getDom(Ext.History.fieldId);
        if (oldIEMode) {
            iframe = Ext.getDom(Ext.History.iframeId);
        }
        this.addEvents(
            /**
             * @event ready
             * Fires when the Ext.History singleton has been initialized and is ready for use.
             * @param {Ext.History} The Ext.History singleton.
             */
            'ready',
            /**
             * @event change
             * Fires when navigation back or forwards within the local page's history occurs.
             * @param {String} token An identifier associated with the page state at that point in its history.
             */
            'change'
        );
        if(onReady){
            this.on('ready', onReady, scope, {single:true});
        }
        startUp();
    },

    /**
     * Add a new token to the history stack. This can be any arbitrary value, although it would
     * commonly be the concatenation of a component id and another id marking the specifc history
     * state of that component.  Example usage:
     * <pre><code>
     // Handle tab changes on a TabPanel
     tabPanel.on('tabchange', function(tabPanel, tab){
     Ext.History.add(tabPanel.id + ':' + tab.id);
     });
     </code></pre>
     * @param {String} token The value that defines a particular application-specific history state
     * @param {Boolean} preventDuplicates When true, if the passed token matches the current token
     * it will not save a new history step. Set to false if the same state can be saved more than once
     * at the same history stack location (defaults to true).
     */
    add: function (token, preventDup) {
        if(preventDup !== false){
            if(this.getToken() == token){
                return true;
            }
        }
        if (oldIEMode) {
            return updateIFrame(token);
        } else {
            location.hash = token;
            return true;
        }
    },

    /**
     * Programmatically steps back one step in browser history (equivalent to the user pressing the Back button).
     */
    back: function(){
        history.go(-1);
    },

    /**
     * Programmatically steps forward one step in browser history (equivalent to the user pressing the Forward button).
     */
    forward: function(){
        history.go(1);
    },

    /**
     * Retrieves the currently-active history token.
     * @return {String} The token
     */
    getToken: function() {
        return ready ? currentToken : getHash();
    }
};
})();
Ext.apply(NewHistory, new Ext.util.Observable());
Ext.apply(Ext.History, NewHistory);
于 2013-02-24T13:28:44.463 に答える
1

これは実際にはかなり簡単でした。私は Ext 4.1 をダウンロードし、彼らが Ext.util.History クラスで何をしているのかを調べました。彼らは oldIEMode の変数を定義し、それを 3.4 で Ext.isIE を使用しているすべての条件に使用します。

そこで、ext-all-debug.js の Ext.History クラスを編集し、先頭に次の変数を定義しました。

var oldIEMode = Ext.isIE6 || Ext.isIE7 || !Ext.isStrict && Ext.isIE8;

Ext.isIE をチェックするクラスには 3 つの条件があり、これを oldIEMode に置き換えました。

アプリを再構築してデプロイしたところ、問題は解決しました。

ext-all.js を編集することはベスト プラクティスではありませんが、代わりにこのクラスを上書きできるはずです。

于 2013-02-24T00:51:54.860 に答える