window.location.replace
来避免历史记录,并且在页面锚点上定位而不需要重新加载页面,但是在iframes中无法实现?问题是CSP(内容安全策略)违规,它要求启用
script-src 'unsafe-inline'
。 除非我定义一个CSP并允许script-src 'unsafe-inline'
,否则即使我定义了一个CSP并允许它,它仍然会给出相同的违规错误。 在ie11 / chrome / ff中结果相同。iframe与同一域(在同一目录中)。
- 在控制台中定位iframe,并在控制台中使用
window.location.replace('/samepage.html#onpage_anchor')
。 - 它起作用。 它定位到页面锚点,而不需要重新加载页面并且没有历史记录。
- 将相同的代码内联到锚链接中,它是有效的。
- 将相同的代码用于外部脚本,会得到csp违规错误。 如果不在iframe中,则这很好运行。
因此,我在plunker上制作了示例,以便可以使用引用父/子页面的proper hrefs。
有关plunker示例的注释:
- 这些示例未能在本地服务器上或在VPS上运行。 代码在iframe中无法工作,但是在plunker中可以正常工作。
- 我怀疑CSP违规未能在plunker上触发,因为plunker通过某种抽象层向浏览器呈现内容。
- 第一次单击父级中的手风琴链接会导致刷新。 这是因为页面最初加载时它没有引用index.html。 后续点击将按预期工作而不需要重新加载页面。 在iframe中没有问题,因为它最初是引用child.html的
- 这些示例非常好,可用于在Stack Overflow片段中展示代码,无需更改href即可使其工作。 它也很好,因为它显示了JavaScript应该正常工作的方式。 但它并没有显示实际的问题。 您仍然需要在编辑器中加载它并在本地服务器或实时托管环境中运行它以查看真正的问题。
简单的手风琴只有一个条目。 足以重现问题。
点击打开/关闭将展开/折叠手风琴,无需JS。JS应该做相同的事情,但不包括历史记录。工作正常,但不适用于iframe。
代码片段说明:
您可以运行片段以了解我所描述的内容,但实际上它并没有演示问题。
片段的行为方式与真实浏览器中的不同,javascript不起作用。
片段显示了代码,但应在iframe中运行以查看问题。在iframe之外运行以查看差异和应该如何工作。
由于链接与JS的工作方式(替换整个URL),它们实际上必须像这样
href="/thispage.html#ac1"
而不是只有href="#ac1"
,因为它们出现在片段中(无法针对片段中的实际HTML页面)。因此,如果您在编辑器中尝试此操作(请尝试),则请记住将链接更改为此格式this_document.html#anchor
,以便它们仍然是相同的页面锚点,但是page.html已包括在链接中。
$(document).ready(function() {
// anchor links without history
$.acAnch = function(event) {
event.preventDefault();
var anchLnk = $(event.target);
var anchTrgt = anchLnk.attr('href');
window.location.replace(anchTrgt);
}
// listen for anchor clicks
$('.accordion').on('click', 'a', $.acAnch);
});
div#sample.example .accordion {
margin-left: 50px;
margin-top: 50px;
}
div#sample.example section {
box-sizing: border-box;
clear: both;
position: relative;
display: block;
width: 300px;
height: 32px;
padding: 0;
background-color: #fff;
box-shadow: inset 0 0 1px 1px #000;
overflow: hidden;
}
div#sample.example section:target {
height: auto;
}
div#sample.example a {
box-sizing: border-box;
display: block;
float: right;
width: 50%;
height: 32px;
margin: 0;
padding: 4px;
text-align: center;
font-size: 16px;
color: #000;
background-color: #fff;
box-shadow: inset 0 0 1px 1px #000;
}
div#sample.example p {
box-sizing: border-box;
clear: both;
display: block;
width: 100%;
padding: 16px;
margin: 16px 0 0;
text-align: center;
color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="sample" class="example">
<article class="accordion">
<section id="ac1">
<a href="#ac0" class="ac-close">Close</a>
<a href="#ac1" class="ac-open">Open</a>
<div class="ac-content">
<p>The elephants talking in their sleep kept me up so late.</p>
</div>
</section>
</article>
</div>
$(document).ready(function() {
// anchor links without history
$.acAnch = function(event) {
event.preventDefault();
var anchLnk = $(event.target);
var anchTrgt = anchLnk.attr('href');
window.location.replace(anchTrgt);
}
// listen for anchor clicks
$('.accordion').on('click', 'a', $.acAnch);
});
这很简单:
acAnch
函数获取href
属性并将其放入window.location.replace()
中。- 监听手风琴中锚点的点击事件以运行
acAnch
函数。
所以脚本所做的只是运行window.location.replace('/this_same_page.html#on_page_anchor')
如果您在控制台中输入它,它就可以工作,没有CSP违规。 但是从外部脚本运行它不起作用。
在链接上的内联工作正常:
onclick="event.preventDefault();window.location.replace('/thispage.html#acc0');"
onclick="event.preventDefault();window.location.replace('/thispage.html#acc1');"
将这段代码放在相应的链接上可以完美地工作,但我真的不想使用内联脚本。一定有一种方法可以通过外部脚本来实现。
我尝试在父级页面上运行javascript,而不是在iframe中(当然需要修改以选择子链接)。结果还是出现了CSP错误。
为什么要这样做呢?因为这个网站比示例要复杂得多。iframe中的锚点很好用,但它们会增加历史记录。如果您没有运行上面的javascript代码(或者只是运行了片段),打开并关闭几次手风琴,再使用后退按钮,它将返回到打开关闭状态。
我不介意历史记录,但如果它在一个iframe中,当您离开父页面然后再回到它时,iframe中的历史记录就被破坏了。返回不再通过手风琴状态历史记录,而是不断重新加载iframe。这种行为对用户非常不友好。
如果有其他可行的方法,我并不需要使用location.replace。虽然我已经尝试了许多其他方法,但发现达到相同结果的方法通常会产生相同的错误。
目标很简单,即在iframe中激活页面上的锚点链接,而无需重新加载和历史记录。
内联脚本是有效的。我们可以让它在外部.js文件中工作吗?
<a href="#ac0" class="ac-close">Close</a>
应该可以实现。 - Rafael Herscovici