Javascript 在不滚动页面的情况下修改location.hash

Javascript 在不滚动页面的情况下修改location.hash,javascript,jquery,fragment-identifier,Javascript,Jquery,Fragment Identifier,我们已经有了一些使用ajax加载内容的页面,并且有一些情况下我们需要深入链接到页面。与其拥有指向“用户”的链接并告诉人们单击“设置”,不如将用户链接到user.aspx#settings 为了让人们能够为我们提供正确的链接到各个部分(如技术支持等),我已经将其设置为每当单击按钮时自动修改URL中的哈希值。当然,唯一的问题是,当这种情况发生时,它还会将页面滚动到此元素 有没有办法禁用此功能?下面是我到目前为止是如何做到这一点的 $(function(){ //This emulates a

我们已经有了一些使用ajax加载内容的页面,并且有一些情况下我们需要深入链接到页面。与其拥有指向“用户”的链接并告诉人们单击“设置”,不如将用户链接到user.aspx#settings

为了让人们能够为我们提供正确的链接到各个部分(如技术支持等),我已经将其设置为每当单击按钮时自动修改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;
    });
});
我曾希望
返回false
会阻止页面滚动,但它只会使链接根本无法工作。所以这只是暂时的注释,这样我就可以导航了


有什么想法吗?

我认为这是不可能的。据我所知,浏览器唯一不滚动到已更改的
document.location.hash
的时间是页面中不存在哈希


与您的问题没有直接关系,但它讨论了更改
document.location.hash的典型浏览器行为步骤1:您需要取消使用节点ID,直到设置了hash。这是通过在设置哈希时从节点上移除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 );
}
hash=hash.replace(/^#/,“”);
变量fx,节点=$(“#”+散列);
if(node.length){
node.attr('id','');
外汇=$('')
.css({
位置:'绝对',
可见性:'隐藏',
顶部:$(文档).scrollTop()+'px'
})
.attr('id',哈希)
.附录(文件正文);
}
document.location.hash=散列;
if(node.length){
fx.remove();
attr('id',hash);
}

步骤3:将其包装在插件中,并使用该插件,而不是写入
location.hash

我想我可能已经找到了一个相当简单的解决方案。问题是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.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,这是您原始代码的一个片段:

$("#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")
});

另一种方法是添加一个隐藏在视口顶部的div。然后,在将哈希添加到url之前,将为该div分配哈希的id…这样您就不会得到滚动条。

使用
history.replaceState
history.pushState
*更改哈希。这不会触发到关联元素的跳转

例子

*如果您想要历史向前和向后的支持

历史行为 如果您使用的是
history.pushState
,并且当用户使用浏览器的历史记录按钮(向前/向后)时,您不希望页面滚动,请查看实验性
scrollRestoration
设置(仅限Chrome 46+)

浏览器支持

如果将hashchange事件与哈希解析器一起使用,则可以防止对链接执行默认操作并更改location.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);
});

好吧,这是一个相当古老的话题,但我想我应该插嘴,因为“正确”的答案不适合CSS

此解决方案基本上防止了点击事件移动页面,因此我们可以首先获得滚动位置。然后我们手动添加散列,浏览器会自动触发一个hashchange事件。我们捕获hashchange事件并回滚到正确的位置。回调通过将散列攻击保持在一个位置来分离并防止代码造成延迟

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!
});

以下是我对启用历史记录的选项卡的解决方案:

    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;
            });
并显示最后选定的选项卡:

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的东西,如果没有它,启用历史记录的选项卡将失败。

此解决方案在实际的scrollTop创建一个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();
});

添加到这里是因为更相关的问题都被标记为指向此处的重复项

我的情况更简单:

  • 用户单击链接(
    a[href='#something']
  • 单击处理程序执行:
    e.preventDefault()
  • smoothscroll函数:
    $(“html,body”).stop(true,true)。动画({“scrollTop”:linkoffset.top},scrollspeed,“swing”)
  • 然后
    window.location=link

这样,就会出现滚动,并且在位置更新时不会出现跳转。

呃,我有一个有点粗糙但绝对有效的工作方法。
只需将当前滚动位置存储在临时变量中,然后在更改散列后重置它即可。:)

因此,对于原始示例:

$("#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);
});

仅在文档就绪时将此代码添加到jQuery中

参考:


我最近正在构建一个旋转木马,它依赖于
window.location.hash
来维护状态,并发现当触发
window.onhashchange
事件时,Chrome和webkit浏览器将以笨拙的抖动强制滚动(甚至到不可见的目标)

即使尝试注册停止传播的处理程序:

$(window).on("hashchange", function(e) { 
  e.stopPropogation(); 
  e.preventDefault(); 
});
没有停止默认浏览器行为。 我找到的解决方案是在不触发不良副作用的情况下更改哈希

 $("#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!
});
我有一个sim卡
$(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;
      }
    }
  });
});
$(window).on("hashchange", function(e) { 
  e.stopPropogation(); 
  e.preventDefault(); 
});
 $("#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;
});
$(window).on('hashchange my.hashchange', function(e, newUrl, oldUrl){
  // @todo - do something awesome!
});
<a name="home"></a><a name="firstsection"></a><a name="secondsection"></a><a name="thirdsection"></a> var trimPanel = loadhash.substring(1); //lose the hash var dotSelect = '.' + trimPanel; //replace hash with dot $(dotSelect).addClass("activepanel").show(); //show the div associated with the hash.
$(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 );
    });
});
$(window).on('hashchange', function(){debugger});
    let hash = window.location.hash.replace(/^#/, '');
    let node = $('#' + hash);
    if (node.length) {
        node.attr('id', '');
    }
    if (node.length) {
        node.attr('id', hash);
    }