【问题标题】:Make anchor links refer to the current page when using <base>使用 <base> 时使锚链接指向当前页面
【发布时间】:2011-12-27 20:57:51
【问题描述】:

当我使用 HTML &lt;base&gt; 标记为页面上的所有相对链接定义基本 URL 时,锚链接也直接引用基本 URL。有没有办法设置仍然允许锚链接引用当前打开的页面的基本 URL?

例如,如果我在http://example.com/foo/ 有一个页面:


当前行为:

<base href="http://example.com/" />
<a href="bar/">bar</a> <!-- Links to "http://example.com/bar/" -->
<a href="#baz">baz</a> <!-- Links to "http://example.com/#baz" -->

期望的行为:

<base href="http://example.com/" />
<a href="bar/">bar</a> <!-- Links to "http://example.com/bar/" -->
<a href="#baz">baz</a> <!-- Links to "http://example.com/foo/#baz" -->

【问题讨论】:

  • 您使用的是服务器端编程语言吗?您可以在链接中动态内联当前请求 URI。另见stackoverflow.com/questions/1889076/…
  • @BalusC 我不是,如果可能的话我宁愿避免它。
  • 好吧,如果一切都已经是静态的,那么就使用&lt;a href="foo#baz"&gt;
  • 我不得不说这是大错特错,你将基础设置为http://server/,然后告诉它导航到#baz,它会转到http://server/#baz,这就是相对URL的工作方式,并且这就是使用 &lt;base&gt; 所做的,它改变了相对 URL 的基础。如果这不是你想要的,你的链接不应该是相对的,或者它应该是相对于基础的 href (foo#baz)
  • @JuanMendes 如果“foo”是一个未知的 URL,就会失败。

标签: html href


【解决方案1】:

一点点 jQuery 可能会帮助你。尽管基本 href 可以正常工作,但如果您希望以锚点 (#) 开头的链接是完全相对的,您可以劫持所有链接,检查以 # 开头的链接的 href 属性,然后使用当前 URL 重建它们。

$(document).ready(function () {
    var pathname = window.location.href;
    $('a').each(function () {
       var link = $(this).attr('href');
       if (link.substr(0,1) == "#") {
           $(this).attr('href', pathname + link);
       }
    });
}

【讨论】:

  • 虽然这在某些情况下可能没问题,但我正在制作的网站的人口统计数据可能是 JavaScript 禁用(或不可用)的那种。由于这种情况的唯一后备是破损,这似乎有点令人担忧。
  • 那么,最好的办法是使用来自 baseURL 的完整相对路径对所有链接进行编码,包括锚点。
【解决方案2】:

James Tomasino's answer 的基础上,这个效率稍高一些,解决了 URL 中带有双哈希的错误和语法错误。

$(document).ready(function() {
    var pathname = window.location.href.split('#')[0];
    $('a[href^="#"]').each(function() {
        var $this = $(this),
            link = $this.attr('href');
        $this.attr('href', pathname + link);
    });
});

【讨论】:

    【解决方案3】:

    这是我在生产环境中使用的更短的基于 jQuery 的版本,它对我来说效果很好。

    $().ready(function() {
      $("a[href^='\#']").each(function() {
        this.href = location.href.split("#")[0] + '#' + this.href.substr(this.href.indexOf('#')+1);
      });
    });
    

    【讨论】:

    • 为什么投反对票?它可能并不优雅,但它与此处的其他答案基本相同,但远没有那么简洁但已被投票。
    • 可能有人投了反对票,因为它不适合他们的情况,也不知道如何适应。除了没有提到(假设是 jQuery)库要求之外,我认为这没有任何问题。
    • @Robert 好点。我更新了帖子以反映 jQuery 要求。感谢您的反馈。
    • 在未提及 jQuery 时建议使用 jQuery 会被回避。
    • 虽然这首先是一个学习网站,但程序员应该知道如何将 jquery 转换为 vanilla javascript。特别是因为该线程上的几乎每个示例都依赖于一个或另一个 js 库。图书馆做同样的事情,只是简化从 A 点到 B 点:P 我赞成他的解决方案,因为它是一个完全有效的解决方案 IMO
    【解决方案4】:

    恐怕没有任何服务器端或浏览器端脚本就无法解决这个问题。您可以尝试以下纯 JavaScript(不带 jQuery)实现:

    document.addEventListener("click", function(event) {
      var element = event.target;
      if (element.tagName.toLowerCase() == "a" && 
          element.getAttribute("href").indexOf("#") === 0) {
        element.href = location.href + element.getAttribute("href");
      }
    });
    <base href="https://example.com/">
    
    <a href="/test">/test</a>
    <a href="#test">#test</a>

    它也适用于动态生成(即使用 JavaScript 创建)a 元素(与其他答案不同)。

    【讨论】:

    • @jor 它对我来说很好用。你用的是哪个浏览器?
    • Firefox 47. 我将哈希值连接起来。还尝试打开一个已经包含哈希的 url,然后单击锚链接;这会将其附加到现有哈希中。
    【解决方案5】:

    我在这个网站上找到了一个解决方案:using-base-href-with-anchors,它不需要 jQuery,这是一个可以工作的 sn-p:

    <base href="https://example.com/">
    
    <a href="/test">/test</a>
    <a href="javascript:;" onclick="document.location.hash='test';">Anchor</a>

    或者没有内联 JavaScript,像这样:

    document.addEventListener('DOMContentLoaded', function(){
      var es = document.getElementsByTagName('a')
      for(var i=0; i<es.length; i++){
        es[i].addEventListener('click', function(e) {
          e.preventDefault()
          document.location.hash = e.target.getAttribute('href')
        })
      }
    })
    

    【讨论】:

    • 为什么这是不好的做法?
    • 不好的原因有很多,有的解释了here
    • 使用内联javascript是完全有效的——它的存在是有原因的。该文件中反对它的论点是虚假的。您是否应该将整个大型项目基于内联代码?可能不是。您可以有意使用内联代码并作为边缘案例/gotchya的解决方案吗?绝对地。它是 HTML 规范的一部分是有原因的。由于 HTML 文档的文件大小而全面禁止内联 JS 是货真价实的废话。如果你把相同的代码放在一个外部的 JS 文件中,客户端仍然会下载这些字节。
    • 此解决方案不能很好地降级。在禁用 Javascript(或 html parsers using regex)的浏览器上,您的链接将被破坏。
    【解决方案6】:

    如果你使用 PHP,你可以使用下面的函数来生成锚链接:

    function generateAnchorLink($anchor) {
      $currentURL = "//{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
      $escaped = htmlspecialchars($currentURL, ENT_QUOTES, 'UTF-8');
      return $escaped . '#' . $anchor;
    }
    

    像这样在代码中使用它:

    <a href="<?php echo generateAnchorLink("baz"); ?>">baz</a>
    

    【讨论】:

      【解决方案7】:

      防止在一个 URL 中出现多个#s:

      document.addEventListener("click", function(event) {
        var element = event.target;
        if (element.tagName.toLowerCase() == "a" &&
          element.getAttribute("href").indexOf("#") === 0) {
          my_href = location.href + element.getAttribute("href");
          my_href = my_href.replace(/#+/g, '#');
          element.href = my_href;
        }
      });
      

      【讨论】:

        【解决方案8】:

        如果您使用Angular 2 或更高版本(并且仅针对网络),您可以这样做:

        文件component.ts

        document = document; // Make document available in template
        

        文件component.html

        <a [href]="document.location.pathname + '#' + anchorName">Click Here</a>
        

        【讨论】:

          【解决方案9】:

          您还可以提供绝对 URL:

          <base href="https://example.com/">
          <a href="/test#test">test</a>
          

          而不是这个

          <a href="#test">test</a>
          

          【讨论】:

            【解决方案10】:

            从问题中给出的示例中。为了实现预期的行为,我认为根本不需要使用“base”标签。

            页面位于http://example.com/foo/

            以下代码将提供所需的行为:

            <a href="/bar/">bar</a> <!-- Links to "http://example.com/bar/" -->
            <a href="#baz">baz</a> <!-- Links to "http://example.com/foo/#baz" -->
            

            诀窍是在字符串 href="/bar/" 的开头使用“/”。

            【讨论】:

            • 有些人可能需要 base 标签来构建一个适应用例的视图库,比如在根目录和子目录中运行。删除基本标签不是解决方案。
            【解决方案11】:

            您可以在链接的标签内使用一些 JavaScript 代码。

            <span onclick="javascript:var mytarget=((document.location.href.indexOf('#')==-1)? document.location.href + '#destination_anchor' : document.location.href);document.location.href=mytarget;return false;" style="display:inline-block;border:1px solid;border-radius:0.3rem"
             >Text of link</span>
            

            当用户点击时它是如何工作的?

            1. 首先它检查 URL 中是否已经存在锚点 (#)。在“?”之前测试条件标志。这是为了避免在用户再次单击同一链接时在 URL 中添加两次锚点,因为重定向将不起作用。
            2. 如果现有 URL 中有尖号 (#),则将锚附加到它,并将结果保存在 mytarget 变量中。否则,请保持页面 URL 不变。
            3. 最后,转到mytarget 变量存储的(修改或未更改的)URL。

            除了&lt;span&gt;,您还可以使用&lt;div&gt; 甚至&lt;a&gt; 标签。 我建议避免使用 &lt;a&gt; 以避免在 JavaScript 被禁用或不工作时出现任何不必要的重定向,并使用一些 CSS 样式来模拟 &lt;a&gt; 标记的外观。

            尽管如此,如果您想使用 &lt;a&gt; 标记,请不要忘记在 JavaScript 代码末尾添加 return false; 并像 &lt;a onclick="here the JavaScript code;return false;" href="javascript:return false;"&gt;...&lt;/a&gt; 这样设置 href 属性。

            【讨论】:

              【解决方案12】:

              我的方法是搜索所有指向锚点的链接,并在它们前面加上文档 URL。

              这仅需要在初始页面加载时使用 JavaScript,并保留浏览器功能,例如在新标签页中打开链接。它也并且不依赖于jQuery等。

              document.addEventListener('DOMContentLoaded', function() {
                // Get the current URL, removing any fragment
                var documentUrl = document.location.href.replace(/#.*$/, '')
              
                // Iterate through all links
                var linkEls = document.getElementsByTagName('A')
                for (var linkIndex = 0; linkIndex < linkEls.length; linkIndex++) {
                  var linkEl = linkEls[linkIndex]
              
                  // Ignore links that don't begin with #
                  if (!linkEl.getAttribute('href').match(/^#/)) {
                    continue;
                  }
              
                  // Convert to an absolute URL
                  linkEl.setAttribute('href', documentUrl + linkEl.getAttribute('href'))
                }
              })
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2010-11-27
                • 1970-01-01
                • 2014-11-01
                • 1970-01-01
                • 1970-01-01
                • 2012-08-29
                • 2014-02-20
                相关资源
                最近更新 更多