ドキュメントをジャンプせずにwindow.location.hashを更新するにはどうすればよいですか?


163

ウェブサイトにスライドパネルを設置しています。

アニメーションが終了したら、ハッシュを次のように設定しました

function() {
   window.location.hash = id;
}

(これはコールバックであり、id以前に割り当てられます)。

これは、ユーザーがパネルをブックマークできるようにするために、またJavaScript以外のバージョンが機能するためにうまく機能します。

しかし、ハッシュを更新すると、ブラウザはその場所にジャンプします。これは予想される動作だと思います。

私の質問は、これをどのように防ぐことができますか?つまり、どうすればウィンドウのハッシュを変更できますが、ハッシュが存在する場合はブラウザで要素までスクロールしませんか?ある種のevent.preventDefault()もののようなもの?

私はjQuery 1.4とscrollToプラグインを使用しています

どうもありがとう!

更新

パネルを変更するコードは次のとおりです。

$('#something a').click(function(event) {
    event.preventDefault();
    var link = $(this);
    var id = link[0].hash;

    $('#slider').scrollTo(id, 800, {
        onAfter: function() {

            link.parents('li').siblings().removeClass('active');
            link.parent().addClass('active');
            window.location.hash = id;

            }
    });
});

2
私はあなたが試したと思いますevent.preventDefault():)
Marko

@Markoどこに配置すればいいかわからない!
アレックス

残りのコードを投稿できますか?
Marko

@Marko Ivanovski妥当ではないと思いますが、私は何ができるか見ていきます。
アレックス

3
@Garethハッシュを更新するとすぐに発生するため、そのための場所はないと思います。
アレックス

回答:


261

古いブラウザーにフォールバックする最新のブラウザーで履歴APIを使用することによる回避策があります。

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}

クレジットはLea Verouに送られます


私の意見では、これがより良い答えです。
グレッグアナンデール2014年

10
pushStateには、ブラウザの履歴スタックに状態を追加するという(インデントされた)副作用があることに注意してください。つまり、ユーザーが[戻る]ボタンをクリックしても、popstateイベントリスナーも追加しない限り、何も起こりません。
David Cook

32
@DavidCook- イベントリスナーのhistory.replaceState必要性を回避するために使用することもできます(ハッシュの変更の場合は、これがより意味をなすpopstate場合があります)。
Jack

これでうまくいきました。履歴変更の効果が好きです。これによりhashchangeイベントがトリガーされないという警告を追加したいと思います。それは私が回避しなければならなかったものでした。
ジョーダン

警告!これはhashchangeイベントをトリガーしません
サンティアゴアリスティ

52

問題は、window.location.hashを要素のID属性に設定していることです。「preventDefault()」かどうかに関係なく、ブラウザがその要素にジャンプするのは、予想される動作です。

これを回避する1つの方法は、次のようにハッシュの前に任意の値を付けることです。

window.location.hash = 'panel-' + id.replace('#', '');

次に、ページの読み込み時に接頭辞付きハッシュを確認するだけです。追加のボーナスとして、ハッシュ値を制御できるようになったため、スムーズにスクロールすることもできます...

$(function(){
    var h = window.location.hash.replace('panel-', '');
    if (h) {
        $('#slider').scrollTo(h, 800);
    }
});

これが常に(最初のページのロード時だけでなく)機能する必要がある場合は、関数を使用してハッシュ値の変更を監視し、その場で正しい要素にジャンプできます。

var foundHash;
setInterval(function() {
    var h = window.location.hash.replace('panel-', '');
    if (h && h !== foundHash) {
        $('#slider').scrollTo(h, 800);
        foundHash = h;
    }
}, 100);

2
これは実際に質問に答える唯一のソリューションです-ジャンプせずにハッシュを許可します
amosmos

これは、デフォルトのブラウザの動作によるジャンプを回避するために、ハッシュの任意の値の追加と削除を説明する質問に本当に答えます。
lowtechsun 2016年

1
良い解決策ですが、ブックマークのセクションの使用を無効にするため、OPsの解決策を弱めます
Samus

27

安くて厄介なソリューション..醜い#を使ってください!スタイル。

設定するには:

window.location.hash = '#!' + id;

それを読むには:

id = window.location.hash.replace(/^#!/, '');

ページ内のアンカーまたはIDと一致しないため、ジャンプしません。


3
IE 7とサイトの一部のモバイルバージョンとの互換性を維持する必要がありました。このソリューションは私にとって最もきれいでした。一般的に、私はpushStateソリューションのすべてについて説明します。
Eric Goodwin

1
ハッシュを次のように設定し、window.location.hash = '#/' + id;それを次のwindow.location.hash.replace(/^#\//, '#');ように置き換えると、URLが少しきれいになります-> projects/#/tab1
braitsch

13

現在のスクロール位置を取得して変数に入れ、ハッシュを割り当てて、ページスクロールを元の位置に戻します。

var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;

これはうまくいくはずです


1
ええと、これはしばらくの間私のために働いていましたが、過去数ヶ月の間にこれがFirefoxでの作業をやめました...
matchew

10

次のように、最新のブラウザーにはAttila Fulop(Lea Verou)ソリューションを使用し、古いブラウザーにはGavin Brockソリューションを使用しました。

if (history.pushState) {
    // IE10, Firefox, Chrome, etc.
    window.history.pushState(null, null, '#' + id);
} else {
    // IE9, IE8, etc
    window.location.hash = '#!' + id;
}

Gavin Brockによって観察されたように、IDを取り戻すには、文字列(この場合は "!"がある場合とない場合があります)を次のように扱う必要があります。

id = window.location.hash.replace(/^#!?/, '');

その前に、user706270によって提案されたものと同様のソリューションを試してみましたが、Internet Explorerではうまく機能しませんでした。そのJavaScriptエンジンは非常に高速ではないため、スクロールの増減に気づき、見苦しい視覚効果を生み出します。


2

この解決策は私にとってうまくいきました。

設定の問題location.hashは、ページで見つかった場合、ページがそのIDにジャンプすることです。

問題window.history.pushStateは、ユーザーがクリックする各タブの履歴にエントリを追加することです。次に、ユーザーがbackボタンをと、前のタブに移動します。(これはあなたが望むものかもしれないしそうでないかもしれません。それは私が望んだものではありませんでした)

私にとってreplaceStateは、現在の履歴のみが置き換えられるため、ユーザーがbackボタンをクリックすると前のページに移動するという点で優れたオプションでした。

$('#tab-selector').tabs({
  activate: function(e, ui) {
    window.history.replaceState(null, null, ui.newPanel.selector);
  }
});

MDNのHistory APIドキュメントを確認してください。


1

元の要素を変更できるかどうかはわかりませんが、id attrの使用からdata-idのようなものに切り替えてみませんか?次に、ハッシュ値のdata-idの値を読み取るだけで、ジャンプしません。


1

この解決策は私のために働いた

// store the currently selected tab in the hash value
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
$('#myTab a[href="' + hash + '"]').tab('show');

そして私の完全なjsコードは

$('#myTab a').click(function(e) {
  e.preventDefault();
  $(this).tab('show');
});

// store the currently selected tab in the hash value
$("ul.nav-tabs > li > a").on("shown.bs.tab", function(e) {
  var id = $(e.target).attr("href").substr(1);
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }
   // window.location.hash = '#!' + id;
});

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
// console.log(hash);
$('#myTab a[href="' + hash + '"]').tab('show');

0

laravelフレームワークを使用すると、ハッシュが消去されるため、route-> back()関数を使用すると問題が発生しました。ハッシュを保持するために、簡単な関数を作成しました。

$(function() {   
    if (localStorage.getItem("hash")    ){
     location.hash = localStorage.getItem("hash");
    }
}); 

そして、私は次のように他のJS関数にそれを設定しました:

localStorage.setItem("hash", myvalue);

ローカルストレージの値には、好きな名前を付けることができます。私の名前hash

したがって、ハッシュがPAGE1に設定されている場合、PAGE2に移動します。ハッシュは、PAGE2で[戻る]をクリックすると、PAGE1で再作成されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.