2016-05-24 15 views
4

固定トップメニューとアンカーナビゲーションを使用した1ページレイアウトでは、スクロール時にフラグメント識別子を変更する「scrollspy」があります。スクロールし、Velocity.jsでスクロールをアンカーにアニメートします。スクロールでURLハッシュを変更してボタンを元の状態に戻す

残念なことにブラウザの戻るボタンをクリックすると、スクロールされた方法のすべての手順がわかります。つまり、サイトを読み込んで小さなビットをスクロールしてから、下にスクロールしますが、最後に訪問したIDに戻ったり、実際にブラウザの履歴に戻ることはありません。上記のコードでは

Here is the jsfiddle.

// jQuery on DOM ready 

// In-Page Scroll Animation with VelocityJS 
// ------------------------------------------------ // 
// https://john-dugan.com/fixed-headers-with-hash-links/ 
$('.menu-a').on('click', function(e) { 
    var hash = this.hash, 
     $hash = $(hash) 

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

     $hash.velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], complete: addHash }); 

    e.preventDefault(); 
}); 

// ScrollSpy for Menu items and Fragment Identifier 
// ------------------------------------------------ // 
// https://jsfiddle.net/mekwall/up4nu/ 
$menuLink   = $('.menu-a') 

var lastId, 
    // Anchors corresponding to menu items 
    scrollItems = $menuLink.map(function(){ 
    var item = $($(this).attr("href")); 
     if (item.length) { return item; } 
    }); 


$(window).scroll(function(){ 
    // Get container scroll position 
    var fromTop = $(this).scrollTop()+ 30; // or the value for the #navigation height 

    // Get id of current scroll item 
    var cur = scrollItems.map(function(){ 
     if ($(this).offset().top < fromTop) 
     return this; 
    }); 

    // Get the id of the current element 
    cur = cur[cur.length-1]; 
    var id = cur && cur.length ? cur[0].id : ""; 
    if (lastId !== id) { 
     lastId = id; 

     // Set/remove active class 
     $menuLink 
     .parent().removeClass("active") 
     .end().filter("[href='#"+id+"']").parent().addClass("active"); 
    } 

    // If supported by the browser we can also update the URL 
    // http://codepen.io/grayghostvisuals/pen/EtdwL 
    if (window.history && window.history.pushState) { 
     history.pushState("", document.title,'#'+id); 
    } 
}); 

次正常に動作します:

  • スクロールアニメーションのためのVelocityJSを使用して、メニューのリンクをクリックしたときに、ハッシュまたはフラグメント識別子は、罰金が更新されます。

  • アクティブなクラスは、スクロール時に対応するメニューリンクに与えられます。

  • メニューのリンクをクリックする代わりにスクロールすると、フラグメント識別子も正常に更新されます。

質問
パート1:あなたはフィドルのほんの少しをスクロールし、スクロールを思い出して、スクロールバーがまったく同じように「移動する」ことをあなたが表示されます戻るボタンを押すと、そのされた。

通常のように戻るボタンが必要です。 a)ブラウザの履歴に戻って、表示されていたページ/サイトに戻るか、 b)アンカーリンク(i)をクリックしてからアンカーリンク(ii)をクリックしてから、戻るボタンを押すとアンカーリンク(i)。

パート2:history.pushStateのでIE8でサポートされていない私の代わりにwindow.location.hash = $(this).attr('id');を使用する方法を探しています。私がコードの最後に何をしようとしても、私は単にwindow.location.hash = $(this).attr('id');を働かせることはできません。私は本当にHistoryJSなどを使ってみたいとは思っていませんが、これを学び自分自身で書くことに興味があります。

バックボタンの壊れた動作以外に、私が望む他のすべての動作が既に存在しています。今すぐバックボタンの動作を修正する必要があります。

編集 は、私がテストし、私はこの仕事を得るならば、詳細に返信させていただきます、ソリューションhereを見つけたかもしれないと思います。

関連:
smooth scrolling and get back button with popState on Firefox - need to click twice
jQuery in page back button scrolling
Modifying document.location.hash without page scrolling

How to Detect Browser Back Button event - Cross Browser

答えて

2

あなたはブラウザの履歴を汚染したくない場合は、代わりにhistory.replaceState()を使用することができ、あなたの質問の最初の部分に答えるためにhistory.pushState()pushStateはURLを変更し、ブラウザの履歴に新しいエントリを追加しますが、replaceStateは、新しい履歴エントリを追加するのではなく、現在の履歴エントリを変更しながらURLを変更します。

pushStatereplaceStateon MDNの違いを含む良い記事もあります。

+0

です。また、 'history.pushState'は' window.scroll'関数内にあるため、スクロールイベントによって起動される新しいスクロール位置をブラウザ履歴にプッシュします。私は別のアプローチでこれを解決することができましたが、今私は**これがなぜ起こっているのか知っています。今や意味をなさないまだ研究していますが、私の解決策はフィンガーが交差したときに提示されます。 – lowtechsun

1

古いブラウザでは、https://github.com/devote/HTML5-History-APIを含めることにしました。これにより、多かれ少なかれ、望ましい動作が得られました。

この答えはあります
- スクロール上のものへのメニュー項目とセットとアクティブクラスのスクロールスパイ
- スクロールスパイもあるセクションに応じて、正しいハッシュを設定し、URLハッシュのために働きますユーザがスクロールを停止した時点をチェックし、現在アクティブなメニュー項目から値を取得し、それを現在のURLハッシュとして設定するスクロール停止機能です(
)。これは、スクロール中にセクションのアンカーを捕まえないように、ユーザーがスクロールするセクションのアンカーだけを捕らえるために行われます。
- メニューリンクをクリックしたときや、前後のボタンを使うときに、Velocity.jsで滑らかなスクロール
- 特定のURLハッシュでページを入力したときにページを読み込んで再読み込みする機能セクションの場合、そのセクションへのスクロールをアニメートし、ページがリロードされると、スクロールを現在のセクションの先頭にアニメートします。

コードは大まかなスケッチであり、デモの目的で私はまだ初心者だと思いますを指摘明白な私はそれらから学ぶことができるようにエラー。コードスニペットの元になるすべてのリンクも含まれています。

// In-Page Scroll Animation to Menu Link on click 
// ------------------------------------------------ // 
// https://john-dugan.com/fixed-headers-with-hash-links/ 
// https://stackoverflow.com/questions/8355673/jquery-how-to-scroll-an-anchor-to-the-top-of-the-page-when-clicked 
// http://stackoverflow.com/a/8579673/1010918 
// $('a[href^="#"]').on('click', function(e) { 
$('.menu-a').on('click', function(e) { 

    // default = make hash appear right after click 
    // not default = make hash appear after scrolling animation is finished 
    e.preventDefault(); 

    var hash = this.hash, 
     $hash = $(hash) 

    $hash.velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], queue: false }); 
}); 



// In-Page Scroll Animation to Hash on Load and Reload 
// ----------------------------------------------------------- // 
// https://stackoverflow.com/questions/680785/on-window-location-hash-change 
// hashchange triggers popstate ! 
$(window).on('load', function(e) { 

    var hash = window.location.hash; 
    console.log('hash on window load '+hash); 
    $hash = $(hash) 

    $hash.velocity("scroll", { duration: 500, easing: [ .4, .21, .35, 1 ], queue: false }); 

    // if not URL hash is present = root, go to top of page on reload 
    if (!window.location.hash){ 
     $('body').velocity("scroll", { duration: 500, easing: [ .4, .21, .35, 1 ], queue: false }); 
    } 
}); 



// In-Page Scroll Animation to Hash on Back or Forward Button 
// ---------------------------------------------------------- // 
$('.menu-a').on('click', function(e) { 
    e.preventDefault(); 
    // keep the link in the browser history 
    // set this separately from scrolling animation so it works in IE8 
    history.pushState(null, null, this.href); 
    return false 
}); 
$(window).on('popstate', function(e) { 
    // alert('popstate fired'); 
    $('body').append('<div class="console1">popstate fired</div>'); 
    $('.console1').delay(1000).fadeOut('slow'); 

    if (!window.location.hash){ 
     $('body').append('<div class="console2">no window location hash present</div>'); 

     $('body').velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], queue: false }); 

     $('.console2').delay(1000).fadeOut('slow'); 
    } 

    console.log('window.location.hash = '+window.location.hash); 
    var hash = window.location.hash; 
    $hash = $(hash) 

    $hash.velocity("scroll", { duration: 700, easing: [ .4, .21, .35, 1 ], queue: false }); 
}); 



// ScrollSpy for Menu items only - gives selected Menu items the active class 
// ------------------------------------------------------------------------ // 
// Does not update fragment identifier in URL https://en.wikipedia.org/wiki/Fragment_identifier 
// https://jsfiddle.net/mekwall/up4nu/ 
    var lastId, 

    // Anchors corresponding to menu items 
    scrollItems = $menuLink.map(function(){ 
     var item = $($(this).attr("href")); 
     // console.table(item); 
     if (item.length) { return item; } 
    }); 

    // Give menu item the active class on load of corresponding item 
    function scrollSpy() { 

     // Get container scroll position 
     var fromTop = $(this).scrollTop()+ $menuButtonHeight; 

     // Get id of current scroll item 
     var cur = scrollItems.map(function(){ 
      if ($(this).offset().top < fromTop) 
      return this; 
     }); 

     // Get the id of the current element 
     cur = cur[cur.length - 1]; 
     var id = cur && cur.length ? cur[0].id : ""; 

     if (lastId !== id) { 
      lastId = id; 
      // Set/remove active class 
      $menuLink 
      .parent().removeClass("active").end() 
      .filter("[href='#"+id+"']").parent().addClass("active"); 
     } 

     // Active Menu Link href Attribute 
     activeMenuLinkHref = $('.menu-li.active > .menu-a').attr('href'); 
     // console.log('activeMenuLinkHref '+activeMenuLinkHref); 
    } 
    scrollSpy() 

    $(window).scroll(function(e){ 
     scrollSpy() 
    }); 



// On Stop of Scrolling get Active Menu Link Href and set window.location.hash 
// --------------------------------------------------------------------------- // 

// Scroll Stop Function 
//---------------------// 
// https://stackoverflow.com/questions/8931605/fire-event-after-scrollling-scrollbars-or-mousewheel-with-javascript 
// http://stackoverflow.com/a/8931685/1010918 
// http://jsfiddle.net/fbSbT/1/ 
// http://jsfiddle.net/fbSbT/87/ 

(function(){ 
    var special = jQuery.event.special, 
     uid1 = 'D' + (+new Date()), 
     uid2 = 'D' + (+new Date() + 1); 
    special.scrollstart = { 
     setup: function() { 
      var timer, 
       handler = function(evt) { 
        var _self = this, 
         _args = arguments; 
        if (timer) { 
         clearTimeout(timer); 
        } else { 
         evt.type = 'scrollstart'; 
         // throws "TypeError: jQuery.event.handle is undefined" 
         // jQuery.event.handle.apply(_self, _args); 
         // solution 
         // http://stackoverflow.com/a/20809936/1010918 
         // replace jQuery.event.handle.apply with jQuery.event.dispatch.apply 
         jQuery.event.dispatch.apply(_self, _args); 
        } 
        timer = setTimeout(function(){ 
         timer = null; 
        }, special.scrollstop.latency); 
       }; 
      jQuery(this).bind('scroll', handler).data(uid1, handler); 
     }, 
     teardown: function(){ 
      jQuery(this).unbind('scroll', jQuery(this).data(uid1)); 
     } 
    }; 
    special.scrollstop = { 
     latency: 250, 
     setup: function() { 
      var timer, 
        handler = function(evt) { 
        var _self = this, 
         _args = arguments; 
        if (timer) { 
         clearTimeout(timer); 
        } 
        timer = setTimeout(function(){ 
         timer = null; 
         evt.type = 'scrollstop';       
         // throws "TypeError: jQuery.event.handle is undefined" 
         // jQuery.event.handle.apply(_self, _args); 
         // solution 
         // http://stackoverflow.com/a/20809936/1010918 
         // replace jQuery.event.handle.apply with jQuery.event.dispatch.apply 
         jQuery.event.dispatch.apply(_self, _args); 
        }, special.scrollstop.latency); 
       }; 
      jQuery(this).bind('scroll', handler).data(uid2, handler); 
     }, 
     teardown: function() { 
      jQuery(this).unbind('scroll', jQuery(this).data(uid2)); 
     } 
    }; 

})(); 



// Scroll Stop Function Called 
//----------------------------// 

$(window).on("scrollstop", function() { 

    // window.history.pushState(null, null, activeMenuLinkHref); 
    // window.history.replaceState(null, null, activeMenuLinkHref); 

    // http://stackoverflow.com/a/1489802/1010918 // 
    // works best really 
    hash = activeMenuLinkHref.replace(/^#/, ''); 
    console.log('hash '+hash); 
    var node = $('#' + hash); 
    if (node.length) { 
     node.attr('id', ''); 
     // console.log('node.attr id'+node.attr('id', '')); 
    } 
    document.location.hash = hash; 
    if (node.length) { 
     node.attr('id', hash); 
    } 
}); 

CSS

.console1{ 
    position: fixed; 
    z-index: 9999; 
    top:0; 
    right:0;  
    background-color: #fff; 
    border: 2px solid red; 
} 

.console2{ 
    position: fixed; 
    z-index: 9999; 
    bottom:0; 
    right:0;  
    background-color: #fff; 
    border: 2px solid red; 
} 

私はまた、期限内にjsfiddleを供給します。 ;)

関連する問題