使用 <base> 时使锚链接指向当前页面
Posted
技术标签:
【中文标题】使用 <base> 时使锚链接指向当前页面【英文标题】:Make anchor links refer to the current page when using <base> 【发布时间】:2011-12-27 20:57:51 【问题描述】:当我使用 html <base>
标记为页面上的所有相对链接定义基本 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。另见***.com/questions/1889076/… @BalusC 我不是,如果可能的话我宁愿避免它。 好吧,如果一切都已经是静态的,那么就使用<a href="foo#baz">
。
我不得不说这是大错特错,你将基础设置为http://server/
,然后告诉它导航到#baz
,它会转到http://server/#baz
,这就是相对URL的工作方式,并且这就是使用 <base>
所做的,它改变了相对 URL 的基础。如果这不是你想要的,你的链接不应该是相对的,或者它应该是相对于基础的 href (foo#baz
)
@JuanMendes 如果“foo”是一个未知的 URL,就会失败。
【参考方案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>
当用户点击时它是如何工作的?
-
首先它检查 URL 中是否已经存在锚点 (#)。在“?”之前测试条件标志。这是为了避免在用户再次单击同一链接时在 URL 中添加两次锚点,因为重定向将不起作用。
如果现有 URL 中有尖号 (#),则将锚附加到它,并将结果保存在
mytarget
变量中。否则,请保持页面 URL 不变。
最后,转到mytarget
变量存储的(修改或未更改的)URL。
除了<span>
,您还可以使用<div>
甚至<a>
标签。
我建议避免使用 <a>
以避免在 JavaScript 被禁用或不工作时出现任何不必要的重定向,并使用一些 CSS 样式来模拟 <a>
标记的外观。
尽管如此,如果您想使用 <a>
标记,请不要忘记在 JavaScript 代码末尾添加 return false;
并像 <a onclick="here the JavaScript code;return false;" href="javascript:return false;">...</a>
这样设置 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'))
)
【讨论】:
以上是关于使用 <base> 时使锚链接指向当前页面的主要内容,如果未能解决你的问题,请参考以下文章