2016-05-24 1 views
4

На макете одной страницы с фиксированным верхним меню и привязной навигацией У меня есть «scrollspy» на месте, который изменяет идентификатор фрагмента на прокрутке, дает ссылку меню активному классу в зависимости от прокрутить позицию и оживить прокрутку к якорю с помощью Velocity.js.Изменение URL-адреса хэша на кнопке прокрутки и возврата назад

К сожалению, что бы он ни делал, при нажатии кнопки «Назад» браузера он проходит через все шаги прокрученного пути, то есть я загружаю сайт и прокручиваю вниз и вверх по крошечному биту, а затем часто нажимаю кнопку «Назад» в браузере также будет прокручиваться вниз и вверх, но не перейдет ни к последнему посещенному идентификатору, ни к предыдущей истории браузера.

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-адрес, изменяя текущую запись истории, а не добавляя новую.

Существует также хорошее изделие, включая разницу между pushState и replaceStateon 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 в свое время. ;)

Смежные вопросы