【问题标题】:How can I update window.location.hash without jumping the document?如何在不跳转文档的情况下更新 window.location.hash?
【发布时间】:2011-04-21 16:01:39
【问题描述】:

我在我的网站上设置了一个滑动面板。

当它完成动画时,我像这样设置哈希

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

(这是一个回调,之前分配了id)。

这很好用,允许用户为面板添加书签,并且非 JavaScript 版本也可以工作。

但是,当我更新哈希时,浏览器会跳转到该位置。我猜这是预期的行为。

我的问题是:如何防止这种情况发生? IE。如何更改窗口的哈希值,但如果哈希值存在,让浏览器滚动到元素?某种event.preventDefault() 之类的东西?

我正在使用 jQuery 1.4 和 scrollTo plugin

非常感谢!

更新

这是更改面板的代码。

$('#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;

            }
    });
});

【问题讨论】:

  • 我假设你已经尝试过event.preventDefault() :)
  • @Marko 我不知道该放在哪里!
  • 你能把剩下的代码贴出来吗?
  • @Marko Ivanovski 我认为这无关紧要,但我会看看我能做些什么。
  • @Gareth 我不认为有它的位置,因为它会在我更新哈希时立即发生。

标签: javascript jquery hash scrollto


【解决方案1】:

在现代浏览器上使用历史 API 并回退旧浏览器有一种解决方法:

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

归功于Lea Verou

【讨论】:

  • 我认为这是更好的答案。
  • 请注意,pushState 具有向浏览器历史堆栈添加状态的副作用(缩进)。换句话说,当用户点击后退按钮时,除非你也添加一个 popstate 事件监听器,否则什么都不会发生。
  • @DavidCook - 我们也可以使用history.replaceState(对于散列更改,这可能更有意义)来避免需要popstate 事件监听器。
  • 这对我有用。我喜欢历史变化的效果。我想补充一点,这不会触发hashchange 事件。这是我必须解决的问题。
  • 不需要使用history.pushState 来解决此问题。如果您的:target 元素具有position: fixed,它将从正常流程中删除,因此无处可滚动。然后,您可以使用 window.history.hash = 'foo' 分配哈希值,窗口将保持不变。
【解决方案2】:

问题是您将 window.location.hash 设置为元素的 ID 属性。无论您是否“preventDefault()”,浏览器都会跳转到该元素的预期行为。

解决此问题的一种方法是在哈希前面加上任意值,如下所示:

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

【讨论】:

  • 这是唯一真正回答问题的解决方案——允许散列而不跳转
  • 这确实回答了解释添加和删除哈希的任意值以避免按照默认浏览器行为跳转的问题。
  • 很好的解决方案,但削弱了 OPs 解决方案,因为它否定了书签部分的使用
【解决方案3】:

便宜又讨厌的解决方案.. 使用丑陋的#!风格。

设置它:

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

阅读:

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

由于和页面中的anchor或者id不匹配,所以不会跳转。

【讨论】:

  • 我必须保持与 IE 7 和该网站的某些移动版本的兼容性。这个解决方案对我来说是最干净的。一般来说,我会使用 pushState 解决方案。
  • 将哈希设置为:window.location.hash = '#/' + id;,然后将其替换为:window.location.hash.replace(/^#\//, '#'); 将美化 url -> projects/#/tab1
【解决方案4】:

为什么不获取当前滚动位置,将其放入变量中,然后分配哈希并将页面滚动回到原来的位置:

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

这应该可以工作

【讨论】:

  • 嗯,这对我有用了一段时间,但在过去几个月的某个时候,它已经停止在 firefox 上工作......
【解决方案5】:

我结合了适用于现代浏览器的 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 引擎不是很快,你可以注意到滚动增加和减少,这会产生令人讨厌的视觉效果。

【讨论】:

    【解决方案6】:

    这个解决方案对我有用。

    设置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 docs

    【讨论】:

      【解决方案7】:

      这个解决方案对我有用

      // 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');
      

      【讨论】:

        【解决方案8】:

        我不确定您是否可以更改原始元素,但是如何从使用 id attr 切换到其他诸如 data-id 之类的东西?然后只需为您的哈希值读取 data-id 的值,它就不会跳转。

        【讨论】:

          【解决方案9】:

          在使用 laravel 框架时,我在使用 route->back() 函数时遇到了一些问题,因为它擦除了我的哈希值。为了保留我的哈希值,我创建了一个简单的函数:

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

          我将它设置在我的其他 JS 函数中,如下所示:

          localStorage.setItem("hash", myvalue);
          

          您可以随意命名本地存储值;我的名字叫hash

          因此,如果在 PAGE1 上设置了哈希值,然后您导航到 PAGE2;当您在 PAGE2 上单击返回时,哈希将在 PAGE1 上重新创建。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-05-26
            • 2010-10-13
            • 2020-10-18
            • 2011-09-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多