<details> 跨 iframe 的镜像和复选框状态



我有一个iFrame,它在自己内部加载父页面。所以,同一页的两份拷贝;一个在iFrame中,一个不在。

我试图在主页和iFrame之间镜像<input type="checkbox">checked/unchecked<details>open/closed的状态。

我已经解决了每个部分(参见// comments的问题),触发click事件:

对于复选框,我有

let boxes = document.querySelectorAll('input[type="checkbox"]');
for (let box of boxes)) {
myIFrame.getElementById(box.id).checked = box.checked; // works
if (inIFrame) {parent.getElementById(box.id).checked = document.getElementById(box.id).checked; // doesn't work
}

(上面的条件inIFrame只是检查页面是否在iFrame中加载的测试的简写)

对于<details>

let detailEls = document.querySelectorAll('details');
for (let i = 0; i < detailEls.length; i++) {
myIFrame.querySelectorAll('details')[i].open = querySelectorAll('details')[i].open; // works, but 1-click behind
}

但奇怪的是,它落后了一个点击。因此,如果我点击,点击,点击在主页面打开详细信息A,B,C,只有A,B会在iFrame中打开——下一次点击,C会打开。

如果不是很清楚,这里是我的问题总结:

  1. 为什么<details>状态延迟?这似乎是与复选框相同的策略,但结果是不同的。
  2. 为什么选中的状态只能镜像从主页到iFrame,而不是相反?

谢谢!

下面是演示您想要的行为的复制,通常遵循您的模式:

https://stackblitz.com/edit/so-mirror-iframe?file=lib/script.js

没有完整的代码很难判断,但这里有一些事情需要考虑:

  1. 如果你在细节上使用click事件,这可能会给你带来"延迟"。的行为。事实证明,click事件在其open属性更新之前出现。当你的同步器运行时,你刚刚点击的那个总是在错误的状态下读取。

    • 使用toggle事件代替,在open属性更新后触发
  2. 假设它不是第一个代码块中的错别字,parent是对父窗口的引用,而不是它的文档

    • 使用parent.document.getElementById代替

好的,你使用的逻辑将无法像你想的那样mirror vice-versa,所以我将把它放在click的基础上在WINDOW和IFRAME

这是我的回复,这是一个链接(请在新选项卡中打开)

概念如下:

  • 我在iframe上都创建了mirrored元素的数组window。这些数组以相同的方式生成,以便keys/indexes在单独的窗口中与它们的等效相关联(window.boxes[0]窗口中的第一个框)。childWindow.boxes[0]iframe中的第一个框
  • 现在最重要的部分是async部分,您将在addEventListener块中看到。你会看到我awaittimeout的承诺,持续0 ms,但像这样的异步函数是如何工作的,它会等待,直到它没有阻塞任何东西,然后运行. 这就是为什么它忽略了detail条给
  • 的滞后效应。

window.html

<html><h2>WINDOW</h2>
<iframe id="iframe" width="500" height="300" src="/"></iframe>
<details>.</details>
<details>..</details>
<details>...</details>
<details>....</details>
<details>.....</details>
<input type="checkbox">Hm</input>
<input type="checkbox">Hmm</input>
<input type="checkbox">Hmmm</input>
<input type="checkbox">Hmmmm</input>
<input type="checkbox">Hmmmmm</input>
<script>(async()=>{
window.iframe=document.getElementById('iframe') //iframe
window.childWindow=iframe.contentWindow //window to iframe
window.waitFinish=async function(){ //needful waiting
await new Promise(r=>setTimeout(r,0))
}
window.boxes = [...document.querySelectorAll('input[type="checkbox"]')] //checkboxes
window.details = [...document.querySelectorAll('details')] //details
//wait for iframe to finish loading(if you're doing this manually by the time you begin it'd be finished loading so no worries)
await new Promise(r=>{
let s=setInterval(()=>{
if(typeof childWindow.details=="object"){
clearInterval(s); return r(1)
}
},0)
})
//window to iframe
boxes.forEach((box,index)=>{
box.addEventListener("click",async(ev)=>{
await waitFinish()
childWindow.boxes[index].checked=box.checked
})
})
details.forEach((detail,index)=>{
detail.addEventListener("click",async(ev)=>{
await waitFinish()
childWindow.details[index].open=detail.open
})
})
//iframe to window
childWindow.boxes.forEach((box,index)=>{
box.addEventListener("click",async(ev)=>{
await waitFinish()
window.boxes[index].checked=box.checked
})
})
childWindow.details.forEach((detail,index)=>{
detail.addEventListener("click",async(ev)=>{
await waitFinish()
window.details[index].open=detail.open
})
})
})()</script>
</html>

iframe.html

<html><h2>IFRAME</h2>
<i><a target="_blank" href="https://iframe-mirror.paultaylor2.repl.co">Full Page</a></i>
<details>.</details>
<details>..</details>
<details>...</details>
<details>....</details>
<details>.....</details>
<input type="checkbox">Hm</input>
<input type="checkbox">Hmm</input>
<input type="checkbox">Hmmm</input>
<input type="checkbox">Hmmmm</input>
<input type="checkbox">Hmmmmm</input>
<script>
window.boxes = [...document.querySelectorAll('input[type="checkbox"]')] //checkboxes
window.details = [...document.querySelectorAll('details')] //details
</script>
</html>

你犯了一个小错误。你的代码是:

for (let box of querySelectorAll('input[type="checkbox"]')) {
myIFrame.getElementById(box.id).checked = box.checked; // works
if (inIFrame) {parent.getElementById(box.id).checked = getElementById(box.id).checked; // doesn't work
}

for (let box of querySelectorAll('input[type="checkbox"]')) {
myIFrame.getElementById(box.id).checked = box.checked; // works
if (inIFrame) {parent.getElementById(box.id).checked = document.getElementById(box.id).checked; // works now that it's fixed
}

您忘记了document对象作为父对象。

最新更新