使用JavaScript实现锚点跳转

150

我有一个经常被发现的问题,但没有地方提供明确的解决方案。

我有两个关于锚点的问题。

主要目标应该是在使用锚点跳转页面时获得一个漂亮而干净的URL,而没有任何哈希。

因此,锚点的结构是:

<ul>
    <li><a href="#one">One</a></li>
    <li><a href="#two">Two</a></li>
    <li><a href="#three">Three</a></li>
</ul>

<div class="wrap">
    <a name="one">text 1</a>
    <a name="two">text 2</a>
    <a name="three" class="box">text 3</a>
</div>

好的,如果您点击其中一个链接,url将自动更改为:

www.domain.com/page

最后应该只有这个:

www.domain.com/page

到目前为止,一切都很好。现在第二件事是,当你在互联网上搜索这个问题时,你会发现JavaScript是一个解决方案。

我找到了这个函数:

function jumpto(anchor){
    window.location.href = "#"+anchor;
}

并调用该函数:

<a onclick="jumpto('one');">One</a>

什么将像以前一样。它会向URL添加哈希。我还添加了

<a onclick="jumpto('one'); return false;">

没有成功。所以如果有人能告诉我如何解决这个问题,我会非常感激。

非常感谢。


不确定,但您可以尝试在跳转后手动编写哈希属性。例如,在onclick处理程序中设置一个超时,该超时设置window.location.hash='' - Jeff
你的意思是在同一网页中跳转到另一个部分时,不想在URL中显示#吗? - Roger Ng
2
在这种情况下,您将不得不操作窗口的scrollTop,通常是通过window.scrollTo或相应的jQuery助手:https://dev59.com/d2w15IYBdhLWcg3wVaQa或https://dev59.com/fHRB5IYBdhLWcg3wz6ed - Frank van Puffelen
@Jeff - 如果你执行 location.hash=''# 仍然会保留在那里。 - Derek 朕會功夫
2
请不要这样做。当您将页面保存在书签中时,哈希是很好的选择。 - Marco Sulla
值得注意的是,锚点标签的name属性已被弃用。您应该使用id属性代替。 - Dylan Smith
7个回答

248

您可以获取目标元素的坐标并将滚动位置设置为该坐标。但这太复杂了。

这里有一种更懒的方法:

function jump(h){
    var url = location.href;               //Save down the URL without hash.
    location.href = "#"+h;                 //Go to the target element.
    history.replaceState(null,null,url);   //Don't like hashes. Changing it back.
}

这里使用了replaceState来操纵URL。如果你还想要支持IE浏览器,那么你需要用复杂的方式来实现。

function jump(h){
    var top = document.getElementById(h).offsetTop; //Getting Y of target element
    window.scrollTo(0, top);                        //Go there directly or some transition
}​

演示:http://jsfiddle.net/DerekL/rEpPA/
带有过渡效果的另一个演示:http://jsfiddle.net/DerekL/x3edvp4t/

您还可以使用.scrollIntoView

document.getElementById(h).scrollIntoView();   //Even IE6 supports this

(好吧,我撒谎了。其实并不复杂。)


(注:这段话是在讽刺前面所说的事情其实很简单)

1
糟糕!链接已经失效了 :-( 我以为 JS Fiddles 永远都在那里。 - Mawg says reinstate Monica
1
@Mawg 看起来他们已经删除了在URL末尾添加“/show”的功能。 - Derek 朕會功夫
19
我很乐意为您翻译,以下是翻译的结果:“即使是IE6也支持这个功能”是我见过最好的评论。 - Josh
4
@Black,“jQuery”元素并不存在。如果你想从查询结果中获得第一个元素,可以使用$(mySelector)[0].scrollIntoView()。请注意,这不是一个“jQuery”元素,而是一个原生JavaScript DOM元素。 - Derek 朕會功夫
6
scrollIntoView 得 1 分。将其放在最后提及扣 1 分。 - Yay295
显示剩余11条评论

22
我认为这是一个更加简单的解决方案:
window.location = (""+window.location).replace(/#[A-Za-z0-9_]*$/,'')+"#myAnchor"

这种方法不会重新加载网站,并将焦点设置在屏幕阅读器所需的锚点上。


而在IE上很少有效的东西,在所有IE上都有效 ;) - Adam111p
8
我用以下代码结束:window.location = window.location.origin + window.location.pathname + '#hash'; - Alex
这使页面重新加载了。虽然已接受的答案最终起作用了,但我希望它更短一些。 - HoldOffHunger
这是最好的方式!! - KRISHNA
@Alex 这不是缺少了协议吗? - undefined

7
我没有足够的声望来发表评论。
如果锚点设置了name属性而不是id属性(这在实际情况中并不推荐,但确实会发生),则所选答案中基于getElementById()方法的方法将无法工作。
如果您无法控制文档标记(例如Web扩展程序),请注意此事。
在所选答案中,基于location的方法也可以通过location.replace进行简化。
function jump(hash) { location.replace("#" + hash) }

3
因为在您执行操作时,
window.location.href = "#"+anchor;

当您加载一个新页面时,您可以执行以下操作:

<a href="#" onclick="jumpTo('one');">One</a>
<a href="#" id="one"></a>

<script>

    function getPosition(element){
        var e = document.getElementById(element);
        var left = 0;
        var top = 0;

        do{
            left += e.offsetLeft;
            top += e.offsetTop;
        }while(e = e.offsetParent);

        return [left, top];
    }

    function jumpTo(id){    
        window.scrollTo(getPosition(id));
    }

</script>

5
我认为添加哈希标记并不会使其成为一个新页面。 - Derek 朕會功夫
7
不会重新加载页面。 - Derek 朕會功夫
你说得对,它不会重新加载页面。我在Chrome控制台中尝试了一下,发现网站图标已经重新加载了。 - Jonathan Vukovich-Tribouharet
在最新版本的Firefox中,哈希更改似乎会强制重新加载iFrames(在src属性中)。我认为这是浏览器的一个bug,但需要注意。 - Beejor

2

我有一个按钮,点击它会打开显示对话框,然后我可以输入想要搜索的内容,并跳转到页面上的该位置。它使用Javascript来响应标题。

在.html文件中,我有:

<button onclick="myFunction()">Load Prompt</button>
<span id="test100"><h4>Hello</h4></span>

在.js文件中,我有以下内容:
function myFunction() {
    var input = prompt("list or new or quit");

    while(input !== "quit") {
        if(input ==="test100") {
            window.location.hash = 'test100';
            return;
// else if(input.indexOf("test100") >= 0) {
//   window.location.hash = 'test100';
//   return;
// }
        }
    }
}

当我在提示框中输入test100时,它将跳转到我在html文件中放置的位置。

我使用谷歌浏览器。

注意:这个想法来自于在同一页内进行链接。

<a href="#test100">Test link</a>

点击后将发送到锚点。为了使其多次工作,根据经验需要重新加载页面。

感谢stackoverflow(可能还有stackexchange)的人们,我不记得如何收集所有的碎片了。☺


1
这是我找到的最简单的解决方案,而且非常稳健。
window.location.href = window.location.href.split("#")[0] + "#your-anchor";

这个:
  • scrollToView 不同,不会从URL中删除锚点(更适合分享/用户体验,也有助于分析)
  • 无论URL中当前有多少个哈希标记(0个、1个或20个),都能正常工作,所以如果点击多次也不会失败
  • 不会重新加载页面

0

第一个被接受的解决方案对我来说并没有完全起作用。主要问题是当已经跳转到哈希时,且哈希已经在URL中,再次跳转就不会发生了。为了完整起见,我在这里提出了一个更加详细的解决方案,它可以工作(在Chrome和FF中测试过)。el是带有锚点标签的元素。

        el.addEventListener('click', function(ev) {
            ev.preventDefault();
            const href = ev.target.getAttribute('href');
            const hashIndex = href.indexOf('#');
            if (hashIndex !== -1) {
                const hashPart = href.substring(hashIndex);
                if (location.hash === hashPart) {
                    document.querySelector(hashPart).scrollIntoView();
                }
                else {
                    location.hash = hashPart;
                }
            }
        })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接