89

popstateイベントが発生したときにドキュメントをスクロールするデフォルトの動作を防ぐことは可能ですか?

私たちのサイトはjQueryアニメーションスクロールとHistory.jsを使用しており、状態の変更により、pushstateまたはpopstateを介して、ページのさまざまな領域にユーザーをスクロールする必要があります。問題は、popstateイベントが発生すると、ブラウザが前の状態のスクロール位置を自動的に復元することです。

ドキュメントの幅と高さを100%に設定したコンテナ要素を使用して、そのコンテナ内のコンテンツをスクロールしてみました。私が見つけた問題は、ドキュメントのスクロールほどスムーズではないように見えることです。特にボックスシャドウやグラデーションのようなcss3をたくさん使用する場合。

また、ユーザーがスクロールを開始したときにドキュメントのスクロール位置を保存し、ブラウザーがページをスクロールした後に(ポップステートで)ドキュメントを復元しようとしました。これはFirefox12では正常に機能しますが、Chrome 19では、ページがスクロールされて復元されるためにちらつきがあります。これは、スクロールとスクロールイベントが発生するまでの遅延(スクロール位置が復元される場所)に関係していると思います。

Firefoxはpopstateが起動する前にページをスクロールし(そしてscrollイベントを起動し)、Chromeは最初にpopstateを起動してからドキュメントをスクロールします。

履歴APIを使用している私が見たすべてのサイトは、上記と同様のソリューションを使用するか、ユーザーが前後に移動したときのスクロール位置の変更を無視します(GitHubなど)。

popstateイベントでドキュメントがスクロールされないようにすることは可能ですか?

4

11 に答える 11

76
if ('scrollRestoration' in history) {
  history.scrollRestoration = 'manual';
}

(2015年9月2日にGoogleが発表)

ブラウザのサポート:

Chrome:サポートされています(46以降)

Firefox:サポートされています(46以降)

IE:サポートされていません

エッジ:サポートされています(79以降)

Opera:サポート(33以降)

Safari:サポート

詳細については、MDNでのブラウザの互換性を参照してください。

于 2015-10-08T01:01:40.273 に答える
32

これは、Mozilla開発者コアで1年以上報告されている問題です。残念ながら、チケットは実際には進行しませんでした。Chromeも同じだと思います。これはonpopstateネイティブブラウザの動作であるため、jsを介してスクロール位置に取り組む信頼できる方法はありません。

ただし、スクロール位置が状態オブジェクトに表示されることを明示的に望んでいるHTML5履歴仕様を見ると、将来への希望があります。

履歴オブジェクトは、ブラウジングコンテキストのセッション履歴をセッション履歴エントリのフラットリストとして表します。各セッション履歴エントリは、URLと、オプションで状態オブジェクトで構成され、さらに、タイトル、ドキュメントオブジェクト、フォームデータ、スクロール位置、およびそれに関連付けられたその他の情報を含めることができます。

onpopstateこれと、上記のMozillaチケットに関するコメントを読むと、少なくともを使用している人にとっては、近い将来、スクロール位置が復元されなくなる可能性があることがわかりますpushState

残念ながら、それまでは、pushState使用時にスクロール位置が保存され、スクロール位置がreplaceState置き換えられることはありません。それ以外の場合は、かなり簡単でreplaceState、ユーザーがページをスクロールするたびに現在のスクロール位置を設定するために使用できます(慎重なonscrollハンドラーを使用)。

また、残念ながら、HTML5仕様では、popstateイベントをいつ発生させる必要があるかを正確に指定していません。「セッション履歴エントリに移動すると、特定の場合に発生する」とだけ記載されています。これは、イベントが前か後かを明確に示していません。常に前であれば、ポップステートの後に発生するスクロールイベントを処理するソリューションが可能です。

スクロールイベントをキャンセルしますか?

さらに、スクロールイベントがキャンセル可能であれば、それは簡単ではありません。もしそうなら、シリーズの最初のスクロールイベントをキャンセルするだけでよく(ユーザーのスクロールイベントはレミングのようなもので、数十個ありますが、履歴の再配置によって発生するスクロールイベントは1つです)、問題ありません。

今のところ解決策はありません

私が見る限り、今のところ私がお勧めするのは、HTML5仕様が完全に実装されるのを待って、この場合はブラウザーの動作に合わせてロールすることだけです。つまり、ブラウザーでスクロールが許可されたら、スクロールをアニメートします。 、履歴イベントが発生したときにブラウザにページの位置を変更させます。位置に関して影響を与えることができる唯一のことはpushState、ページが戻るのに良い方法で配置されているときに使用することです。他の解決策は、バグがあるか、ブラウザ固有であるか、またはその両方である必要があります。

于 2012-08-20T21:05:14.717 に答える
4

ここでは、ある種の恐ろしいブラウザスニッフィングを使用する必要があります。Firefoxの場合、スクロール位置を保存して復元するというソリューションを使用します。

あなたの説明に基づいて、優れたWebkitソリューションがあると思いましたが、Chrome 21で試したところ、Chromeが最初にスクロールし、次にpopstateイベントが発生し、次にスクロールイベントが発生したようです。しかし、参考のために、これが私が思いついたものです:

function noScrollOnce(event) {
    event.preventDefault();
    document.removeEventListener('scroll', noScrollOnce);
}
window.onpopstate = function () {
    document.addEventListener('scroll', noScrollOnce);
};​

配置された要素を移動してページをスクロールしているふりをするなどの黒魔術はabsolute、画面の再描画速度によっても除外されます。

ですから、答えはあなたができないということであると私は99%確信しています、そしてあなたはあなたが質問で言及した妥協の1つを使わなければならないでしょう。両方のブラウザは、JavaScriptがそれについて何かを知る前にスクロールするため、JavaScriptはイベント後にのみ反応できます。唯一の違いは、FirefoxはJavascriptが起動するまで画面をペイントしないことです。そのため、Firefoxには実行可能なソリューションがありますが、WebKitにはありません。

于 2012-08-20T11:16:08.333 に答える
3

今、あなたはすることができます

history.scrollRestoration = 'manual';

これにより、ブラウザのスクロールが防止されます。これは現在Chrome46以降でのみ機能しますが、Firefoxもサポートする予定のようです。

于 2015-12-25T16:18:34.877 に答える
2

解決策は、ページのスクロール位置に等しいものを使用position: fixedして指定することです。top

次に例を示します。

$(window).on('popstate', function()
{
   $('.yourWrapAroundAllContent').css({
      position: 'fixed',
      top: -window.scrollY
   });

   requestAnimationFrame(function()
   {
      $('.yourWrapAroundAllContent').css({
         position: 'static',
         top: 0
      });          
   });
});

はい、代わりに点滅するスクロールバーが表示されますが、それほど悪ではありません。

于 2014-06-06T13:01:35.517 に答える
1

次の修正は、すべてのブラウザで機能するはずです。

アンロードイベントでスクロール位置を0に設定できます。このイベントについては、 https ://developer.mozilla.org/en-US/docs/Web/Events/unloadで読むことができます。基本的に、アンロードイベントは、ページを離れる直前に発生します。

アンロード時にscrollPositionを0に設定すると、pushStateが設定された状態でページを離れると、scrollPositionが0に設定されます。更新または押し戻すことでこのページに戻ると、自動スクロールされません。

//Listen for unload event. This is triggered when leaving the page.
//Reference: https://developer.mozilla.org/en-US/docs/Web/Events/unload
window.addEventListener('unload', function(e) {
    //set scroll position to the top of the page.
    window.scrollTo(0, 0);
});
于 2015-10-20T15:41:17.413 に答える
1

scrollRestorationをmanualに設定しても機能しませんでした。これが、私の解決策です。

window.addEventListener('popstate', function(e) {
    var scrollTop = document.body.scrollTop;
    window.addEventListener('scroll', function(e) {
        document.body.scrollTop = scrollTop;
    });
});
于 2016-06-21T13:48:49.007 に答える
0

ページ上部のどこかに「span」要素を作成し、ロード時にこれにフォーカスを設定します。ブラウザは、フォーカスされた要素までスクロールします。これは回避策であり、「スパン」に焦点を当てることがすべてのブラウザで機能するとは限らないことを理解しています(うーん..Safari)。お役に立てれば。

于 2013-01-05T17:42:01.533 に答える
0

ポストステートが起動されたときにスクロール位置を特定の要素にフォーカスさせたいサイトに実装したものは次のとおりです(戻るボタン)。

$(document).ready(function () {

     if (window.history.pushState) {
        //if push supported - push current page onto stack:
        window.history.pushState(null, document.title, document.location.href);
    }

    //add handler:
    $(window).on('popstate', PopStateHandler);
}

//fires when the back button is pressed:
function PopStateHandler(e) {
    emnt= $('#elementID');
    window.scrollTo(0, emnt.position().top);
    alert('scrolling to position');
}

Firefoxでテストされ、動作します。

Chromeはスクロールして所定の位置に移動しますが、その後、元の位置に再配置します。

于 2013-02-04T13:04:13.620 に答える
0

他の人が言ったように、それを行う実際の方法はなく、醜いハッキーな方法だけです。スクロールイベントリスナーを削除してもうまくいかなかったので、これが私の醜い方法です。

/// GLOBAL VARS ////////////////////////
var saveScrollPos = false;
var scrollPosSaved = window.pageYOffset;
////////////////////////////////////////

jQuery(document).ready(function($){

    //// Go back with keyboard shortcuts ////
    $(window).keydown(function(e){
        var key = e.keyCode || e.charCode;

        if((e.altKey && key == 37) || (e.altKey && key == 39) || key == 8)
        saveScrollPos = false;
    });
    /////////////////////////////////////////

    //// Go back with back button ////
    $("html").bind("mouseout",  function(){ saveScrollPos = false; });
    //////////////////////////////////

    $("html").bind("mousemove", function(){ saveScrollPos = true; });

    $(window).scroll(function(){
        if(saveScrollPos)
        scrollPosSaved = window.pageYOffset;
        else
        window.scrollTo(0, scrollPosSaved);
    });

});

Chrome、FF、IEで動作します(IEに初めて戻ったときに点滅します)。改善の提案は大歓迎です!お役に立てれば。

于 2014-08-01T19:41:15.537 に答える
-5

これを試してみませんか?

window.onpopstate = function(event) {
  return false;
};
于 2012-08-15T22:00:31.090 に答える