[英]Nuxt.js global events emitted from page inside iframe are not available to parent page
I'm trying to create a pattern library app that displays components inside iframe
elements, alongside their HTML. 我正在尝试创建一个模式库应用,以在iframe
元素内及其HTML旁边显示组件。 Whenever the contents of an iframe
changes, I want the page containing the iframe
to respond by re-fetching the iframe
's HTML and printing it to the page. 每当iframe
的内容发生变化时,我都希望包含iframe
的页面通过重新获取iframe
的HTML并将其打印到页面iframe
做出响应。 Unfortunately, the page has no way of knowing when components inside its iframe
change. 不幸的是,该页面无法知道其iframe
组件何时更改。 Here's a simplified example of how things are setup: 这是一个简单的示例,说明如何设置:
I have an "accordion" component that emits a global event on update: 我有一个“手风琴”组件,它在更新时发出全局事件:
components/Accordion.vue 组件/Accordion.vue
<template>
<div class="accordion"></div>
</template>
<script>
export default {
updated() {
console.log("accordion-updated event emitted");
this.$root.$emit("accordion-updated");
}
}
</script>
I then pull that component into a page: 然后,我将该组件拉入页面:
pages/components/accordion.vue 页面/组件/accordion.vue
<template>
<accordion/>
</template>
<script>
import Accordion from "~/components/Accordion.vue";
export default {
components: { Accordion }
}
</script>
I then display that page inside an iframe
on another page: 然后,我在另一页的iframe
显示该页:
pages/documentation/accordion.vue pages / documentation / accordion.vue
<template>
<div>
<p>Here's a live demo of the Accordion component:</p>
<iframe src="/components/accordion"></iframe>
</div>
</template>
<script>
export default {
created() {
this.$root.$on("accordion-updated", () => {
console.log("accordion-updated callback executed");
});
},
beforeDestroy() {
this.$root.$off("accordion-updated");
}
}
</script>
When I edit the "accordion" component, the "event emitted" log appears in my browser's console, so it seems like the accordion-updated
event is being emitted. 当我编辑“手风琴”组件时,“事件已发出”日志出现在浏览器的控制台中,因此似乎正在发出accordion-updated
事件。 Unfortunately, I never see the "callback executed" console log from the event handler in the documentation/accordion
page. 不幸的是,我从没有在documentation/accordion
页面的事件处理程序中看到“已执行回调”控制台日志。 I've tried using both this.$root.$emit
/ this.$root.$on
and this.$nuxt.$emit
/ this.$nuxt.$on
and neither seem to be working. 我已经尝试过使用this.$root.$emit
/ this.$root.$on
和this.$nuxt.$emit
/ this.$nuxt.$on
两者都没有用。
Is it possible that each page contains a separate Vue instance, so the iframe
page's this.$root
object is not the same as the documentation/accordion
page's this.$root
object? 每个页面是否可能包含一个单独的Vue实例,所以iframe
页面的this.$root
对象与documentation/accordion
页面的this.$root
对象不同吗? If so, then how can I solve this problem? 如果是这样,那我该如何解决呢?
It sounds like I was correct and there are indeed two separate Vue instances in my iframe
page and its parent page: https://forum.vuejs.org/t/eventbus-from-iframe-to-parent/31299 听起来我是对的,并且在我的iframe
页面及其父页面中确实有两个单独的Vue实例: https : //forum.vuejs.org/t/eventbus-from-iframe-to-parent/31299
So I ended up attaching a MutationObserver
to the iframe
, like this: 因此,我最终将MutationObserver
附加到iframe
,如下所示:
<template>
<iframe ref="iframe" :src="src" @load="onIframeLoaded"></iframe>
</template>
<script>
export default {
data() {
return { iframeObserver: null }
},
props: {
src: { type: String, required: true }
},
methods: {
onIframeLoaded() {
this.getIframeContent();
this.iframeObserver = new MutationObserver(() => {
window.setTimeout(() => {
this.getIframeContent();
}, 100);
});
this.iframeObserver.observe(this.$refs.iframe.contentDocument, {
attributes: true, childList: true, subtree: true
});
},
getIframeContent() {
const iframe = this.$refs.iframe;
const html = iframe.contentDocument.querySelector("#__layout").innerHTML;
// Print HTML to page
}
},
beforeDestroy() {
if (this.iframeObserver) {
this.iframeObserver.disconnect();
}
}
}
</script>
Attaching the observer directly to the contentDocument
means that my event handler will fire when elements in the document's <head>
change, in addition to the <body>
. 将观察者直接附加到contentDocument
意味着,除了<body>
之外,当文档的<head>
中的元素发生更改时,我的事件处理程序也会触发。 This allows me to react when Vue injects new CSS or JavaScript blocks into the <head>
(via hot module replacement). 当Vue将新的CSS或JavaScript块注入<head>
(通过热模块替换)时,这使我能够做出反应。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.