我有一个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会打开。
如果不是很清楚,这里是我的问题总结:
- 为什么
<details>
状态延迟?这似乎是与复选框相同的策略,但结果是不同的。 - 为什么选中的状态只能镜像从主页到iFrame,而不是相反?
谢谢!
下面是演示您想要的行为的复制,通常遵循您的模式:
https://stackblitz.com/edit/so-mirror-iframe?file=lib/script.js
没有完整的代码很难判断,但这里有一些事情需要考虑:
如果你在细节上使用
click
事件,这可能会给你带来"延迟"。的行为。事实证明,click
事件在其open
属性更新之前出现。当你的同步器运行时,你刚刚点击的那个总是在错误的状态下读取。- 使用
toggle
事件代替,在open
属性更新后触发
- 使用
假设它不是第一个代码块中的错别字,
parent
是对父窗口的引用,而不是它的文档。- 使用
parent.document.getElementById
代替
- 使用
好的,你使用的逻辑将无法像你想的那样mirror vice-versa
,所以我将把它放在click
的基础上在WINDOW和IFRAME上
这是我的回复,这是一个链接(请在新选项卡中打开)
概念如下:
- 我在
iframe
和上都创建了mirrored
元素的数组window
。这些数组以相同的方式生成,以便keys/indexes
在单独的窗口中与它们的等效相关联(window.boxes[0]
是窗口中的第一个框)。childWindow.boxes[0]
是iframe中的第一个框 - 现在最重要的部分是
async
部分,您将在addEventListener
块中看到。你会看到我await
的timeout
的承诺,持续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
对象作为父对象。