修改document.location.hash而不滚动页面

我们有几页使用Ajax来加载内容,有几个需要深入链接到一个页面的场合。 而不是链接到“用户”,并告诉人们点击“设置”,这有助于能够将用户链接到user.aspx#设置

为了让人们能够为我们提供正确的部分链接(对于技术支持等),我已经设置了每当单击button时自动修改URL中的哈希值。 当然唯一的问题是,当发生这种情况时,它也滚动页面到这个元素。

有没有办法来禁用这个? 以下是我如何做到这一点。

$(function(){ //This emulates a click on the correct button on page load if(document.location.hash){ $("#buttons li a").removeClass('selected'); s=$(document.location.hash).addClass('selected').attr("href").replace("javascript:",""); eval(s); } //Click a button to change the hash $("#buttons li a").click(function(){ $("#buttons li a").removeClass('selected'); $(this).addClass('selected'); document.location.hash=$(this).attr("id") //return false; }); }); 

我本来希望这个return false; 将停止滚动页面 – 但它只是使链接不工作。 所以现在只是注释掉了,所以我可以导航。

有任何想法吗?

步骤1:您需要化解节点ID,直到哈希已经设置。 这是通过在哈希被设置的时候从节点上去除ID来完成的,然后重新添加它。

 hash = hash.replace( /^#/, '' ); var node = $( '#' + hash ); if ( node.length ) { node.attr( 'id', '' ); } document.location.hash = hash; if ( node.length ) { node.attr( 'id', hash ); } 

步骤2:一些浏览器会根据上次看到的ID节点的位置触发滚动,所以您需要帮助他们一点点。 您需要在视口的顶部添加一个额外的div ,将其ID设置为散列,然后将所有内容都回滚:

 hash = hash.replace( /^#/, '' ); var fx, node = $( '#' + hash ); if ( node.length ) { node.attr( 'id', '' ); fx = $( '<div></div>' ) .css({ position:'absolute', visibility:'hidden', top: $(document).scrollTop() + 'px' }) .attr( 'id', hash ) .appendTo( document.body ); } document.location.hash = hash; if ( node.length ) { fx.remove(); node.attr( 'id', hash ); } 

第3步:将其包装在一个插件,并使用它,而不是写入location.hash

我想我可能find了一个相当简单的解决scheme。 问题是URL中的哈希值也是滚动到的页面上的一个元素。 如果我只是将一些文本join到散列中,现在不再引用现有的元素!

 $(function(){ //This emulates a click on the correct button on page load if(document.location.hash){ $("#buttons li a").removeClass('selected'); s=$(document.location.hash.replace("btn_","")).addClass('selected').attr("href").replace("javascript:",""); eval(s); } //Click a button to change the hash $("#buttons li a").click(function(){ $("#buttons li a").removeClass('selected'); $(this).addClass('selected'); document.location.hash="btn_"+$(this).attr("id") //return false; }); }); 

现在URL显示为page.aspx#btn_elementID ,它不是页面上的真实ID。 我只是删除“btn_”并获得实际的元素ID

使用history.replaceStatehistory.pushState *来更改散列。 这不会触发跳转到关联的元素。

 $(document).on('click', 'a[href^=#]', function(event) { event.preventDefault(); history.pushState({}, '', this.href); }); 

在JSFiddle上演示

*如果你想历史的前进和后退的支持

历史行为

如果您正在使用history.pushState并且在用户使用浏览器的历史loggingbutton(向前/向后)时不想滚动页面,请查看实验性scrollRestoration 恢复设置(仅适用于Chrome 46+)

 history.scrollRestoration = 'manual'; 
  • 规范
  • 信息

浏览器支持

  • replaceState
  • pushState的
  • 填充工具

您的原始代码片段:

 $("#buttons li a").click(function(){ $("#buttons li a").removeClass('selected'); $(this).addClass('selected'); document.location.hash=$(this).attr("id") }); 

将其更改为:

 $("#buttons li a").click(function(e){ // need to pass in "e", which is the actual click event e.preventDefault(); // the preventDefault() function ... prevents the default action. $("#buttons li a").removeClass('selected'); $(this).addClass('selected'); document.location.hash=$(this).attr("id") }); 

我最近build立了一个依靠window.location.hash维护状态的传送带,并发现当window.onhashchange事件被触发时,Chrome和webkit浏览器将强制滚动(甚至是不可见的目标)。

甚至试图注册一个停止传播的处理程序:

 $(window).on("hashchange", function(e) { e.stopPropogation(); e.preventDefault(); }); 

没有什么可以阻止默认的浏览器行为。 我find的解决scheme是使用window.history.pushState更改散列,而不会触发不良的副作用。

  $("#buttons li a").click(function(){ var $self, id, oldUrl; $self = $(this); id = $self.attr('id'); $self.siblings().removeClass('selected'); // Don't re-query the DOM! $self.addClass('selected'); if (window.history.pushState) { oldUrl = window.location.toString(); // Update the address bar window.history.pushState({}, '', '#' + id); // Trigger a custom event which mimics hashchange $(window).trigger('my.hashchange', [window.location.toString(), oldUrl]); } else { // Fallback for the poors browsers which do not have pushState window.location.hash = id; } // prevents the default action of clicking on a link. return false; }); 

然后,您可以监听正常的hashchange事件和my.hashchange

 $(window).on('hashchange my.hashchange', function(e, newUrl, oldUrl){ // @todo - do something awesome! }); 

好吧,这是一个相当古老的话题,但是我认为我会认为“正确的”答案不适合CSS。

这个解决scheme基本上防止了点击事件移动页面,所以我们可以先滚动位置。 然后我们手动添加散列,浏览器自动触发一个hashchange事件。 我们捕获hashchange事件并回滚到正确的位置。 一个callback分离和防止你的代码造成的延迟,保持你的散列黑客入侵。

 var hashThis = function( $elem, callback ){ var scrollLocation; $( $elem ).on( "click", function( event ){ event.preventDefault(); scrollLocation = $( window ).scrollTop(); window.location.hash = $( event.target ).attr('href').substr(1); }); $( window ).on( "hashchange", function( event ){ $( window ).scrollTop( scrollLocation ); if( typeof callback === "function" ){ callback(); } }); } hashThis( $( ".myAnchor" ), function(){ // do something useful! }); 

呃,我有一个粗略,但绝对工作的方法。
只需将当前滚动位置存储在一个临时variables中,然后在更改散列值后重置它。 🙂

所以对于最初的例子:

 $("#buttons li a").click(function(){ $("#buttons li a").removeClass('selected'); $(this).addClass('selected'); var scrollPos = $(document).scrollTop(); document.location.hash=$(this).attr("id") $(document).scrollTop(scrollPos); }); 

我不认为这是可能的。 据我所知,唯一一次浏览器不滚动到一个变化的document.location.hash是如果散列不存在于页面内。

本文与您的问题没有直接关系,但讨论了更改document.location.hash典型浏览器行为

如果使用散列分析器的hashchange事件,可以防止对链接的默认操作和更改位置.hash添加一个字符与元素的id属性有差异

 $('a[href^=#]').on('click', function(e){ e.preventDefault(); location.hash = $(this).attr('href')+'/'; }); $(window).on('hashchange', function(){ var a = /^#?chapter(\d+)-section(\d+)\/?$/i.exec(location.hash); }); 

在这里添加这个,因为更相关的问题都被标记为重复指向这里…

我的情况比较简单:

  • 用户点击链接( a[href='#something']
  • 点击处理程序: e.preventDefault()
  • 平滑滚动函数: $("html,body").stop(true,true).animate({ "scrollTop": linkoffset.top }, scrollspeed, "swing" );
  • 那么 window.location = link;

这样,滚动就会发生,当位置更新时不会跳转。

另一种方法是添加一个隐藏在视口顶部的div。 这个div然后被分配的散列之前哈希被添加到url….所以你不会得到滚动。

这是我的解决scheme启用历史启用标签:

  var tabContainer = $(".tabs"), tabsContent = tabContainer.find(".tabsection").hide(), tabNav = $(".tab-nav"), tabs = tabNav.find("a").on("click", function (e) { e.preventDefault(); var href = this.href.split("#")[1]; //mydiv var target = "#" + href; //#myDiv tabs.each(function() { $(this)[0].className = ""; //reset class names }); tabsContent.hide(); $(this).addClass("active"); var $target = $(target).show(); if ($target.length === 0) { console.log("Could not find associated tab content for " + target); } $target.removeAttr("id"); // TODO: You could add smooth scroll to element document.location.hash = target; $target.attr("id", href); return false; }); 

并显示最后select的标签:

 var currentHashURL = document.location.hash; if (currentHashURL != "") { //a tab was set in hash earlier // show selected $(currentHashURL).show(); } else { //default to show first tab tabsContent.first().show(); } // Now set the tab to active tabs.filter("[href*='" + currentHashURL + "']").addClass("active"); 

请注意filter调用中的*= 。 这是一个jQuery的具体事情,没有它,你的历史启用选项卡将失败。

此解决scheme在实际的scrollTop中创build一个div,并在更改散列之后将其删除:

 $('#menu a').on('click',function(){ //your anchor event here var href = $(this).attr('href'); window.location.hash = href; if(window.location.hash == href)return false; var $jumpTo = $('body').find(href); $('body').append( $('<div>') .attr('id',$jumpTo.attr('id')) .addClass('fakeDivForHash') .data('realElementForHash',$jumpTo.removeAttr('id')) .css({'position':'absolute','top':$(window).scrollTop()}) ); window.location.hash = href; }); $(window).on('hashchange', function(){ var $fakeDiv = $('.fakeDivForHash'); if(!$fakeDiv.length)return true; $fakeDiv.data('realElementForHash').attr('id',$fakeDiv.attr('id')); $fakeDiv.remove(); }); 

可选,在页面加载时触发锚点事件:

 $('#menu a[href='+window.location.hash+']').click(); 

我有一个更简单的方法,适合我。 基本上,请记住HTML中的散列实际上是什么。 这是一个名称标签的锚链接。 这就是为什么它滚动浏览器试图滚动到锚链接。 所以,给它一个!

  1. 在BODY标签下面,放入你的版本:
  <a name="home"> </a> <a name="firstsection"> </a> <a name="secondsection"> </a> <a name="thirdsection"> </a> 
  1. 用类而不是ID来命名你的部分div。

  2. 在您的处理代码中,去掉散列标记并replace为一个点:

     var trimPanel = loadhash.substring(1);  //丢失散列

     var dotSelect ='。'  + trimPanel;  //用点replace散列

     $(dotSelect).addClass( “activepanel”)显示();  //显示与散列关联的div。

最后,移除element.preventDefault或返回:false并允许导航发生。 窗口将停留在顶部,哈希将被添加到地址栏url,并打开正确的面板。

我认为你需要重置滚动到hashchange之前的位置。

 $(function(){ //This emulates a click on the correct button on page load if(document.location.hash) { $("#buttons li a").removeClass('selected'); s=$(document.location.hash).addClass('selected').attr("href").replace("javascript:",""); eval(s); } //Click a button to change the hash $("#buttons li a").click(function() { var scrollLocation = $(window).scrollTop(); $("#buttons li a").removeClass('selected'); $(this).addClass('selected'); document.location.hash = $(this).attr("id"); $(window).scrollTop( scrollLocation ); }); }); 

只有在准备好的文档中添加这个代码到jQuery中

Ref: http : //css-tricks.com/snippets/jquery/smooth-scrolling/

 $(function() { $('a[href*=#]:not([href=#])').click(function() { if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) { var target = $(this.hash); target = target.length ? target : $('[name=' + this.hash.slice(1) +']'); if (target.length) { $('html,body').animate({ scrollTop: target.offset().top }, 1000); return false; } } }); });