Javascript Iframe加载事件触发两次

Javascript Iframe加载事件触发两次,javascript,vue.js,iframe,Javascript,Vue.js,Iframe,绑定到@load=myFunction的函数在创建iframe时触发一次,在实际加载时触发一次 为什么在创建iframe时会触发它,以及如何避免它 <template> <transition name="modal"> <div v-if="webviewOpen"> <transition name="content" appear> <d

绑定到@load=myFunction的函数在创建iframe时触发一次,在实际加载时触发一次

为什么在创建iframe时会触发它,以及如何避免它

<template>
  <transition name="modal">
    <div v-if="webviewOpen">
      <transition name="content" appear>
        <div v-if="webviewOpen">
            <transition name="iframe">
            <iframe
              v-show="showIframe"
              :src="webviewUrl"
              @load="iframeIsLoaded"
            />
          </transition>
        </div>
      </transition>
    </div>
  </transition>
</template>

<script>
import { mapState } from 'vuex'

export default {
  data () {
    return {
      showIframe: false
    }
  },
  computed: {
    ...mapState({
      webviewOpen: state => state.webview.open,
      webviewUrl: state => state.webview.url
    })
  },
  watch: {
    webviewOpen () {
      setTimeout(() => {
        this.showIframe = true
      }, 1000)
    }
  },
  methods: {
    iframeIsLoaded () {
      console.log('iframe loaded')
    }
  }
}
</script>

当safari/chrome在父级上添加到DOM v-if并加载内容时,可能会触发两次safari/chrome,这似乎是一个web工具包问题。将.once修饰符添加到@load.once=myFunction可能会有所帮助,我们从您的示例中了解到,除非在将iframe附加到DOM之后附加侦听器,否则Chrome会显示此问题。要做到这一点,我们可以利用Vue的优势。我们希望它发生在iframe添加到DOM之后,但在它有机会加载之前,因此我们将使用更新的钩子

我在我的任何浏览器中都没有遇到过这个问题,所以很遗憾,我不能真正为您测试它。自己测试一下,看看这样的东西是否能帮你解决问题:

<template>
  <label for="show">Show iFrame</label>
  <input id="show" type="checkbox" v-model="webviewOpen">
  <div v-if="webviewOpen">
    <iframe
      src="https://motherfuckingwebsite.com/"
      @load="iframeLoadHelper"
      frameborder="0"
    ></iframe>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      webviewOpen: false,
      iframeReady: false
    };
  },
  methods: {
    // Helper method, just to keep 'if' outside of the logic of your potentially
    // complex @load method
    iframeLoadHelper() {
      if (this.iframeReady) return this.iframeLoaded();
      else return; // do nothing
    },
    // The real load method
    iframeLoaded() {
      console.log('iframe loaded');
    }
  },
  updated() {
    console.log('changing ready-state');
    this.iframeReady = this.webviewOpen;
  }
};
</script>

<style>
:root { font-family: sans-serif; }
</style>

正如@tao所暗示的,还有一件事正在发生,那就是包裹。因此,如果有人使用此包并发现iframes onload事件神秘地触发了两次并找到了此线程:


在模块部分内导入包时,在nuxt.config.js中添加iframes:false。问题解决了

我们需要更多的代码。问题在别处。这段代码只为我加载了一次。仍然只有console.logs为我加载了一次。很明显,许多人都面临着这个问题。我试过这个答案,但它对我不起作用。@drake035,它显然是在最新的Chrome中,使用的是Vue 2.6.12。提供一个指定至少一个在其中执行此操作的浏览器。没有复制的方法,没有人能提供修复。很可能是其他布局结构指令(例如v-if、v-for)导致从DOM中删除,然后再次添加。到目前为止,您发布的内容无法测试。这里有一个粗略的猜测,您的组件以webviewOpen的真实值开始,该值可能很快被更改为虚假值。这可能会导致在执行mounted之前激发@load,如果此时src是falsy,因为加载不需要任何时间。显然,稍后将webviewOpen切换为真实值时,@load将再次触发。这纯粹是猜测,因为您还没有提供重新编程的方法,因此无法进行测试。但是如果假设是真的,初始化webviewOpen为falsy将修复它。谢谢,它现在只在iframe创建时触发一次,而不是在iframe加载时触发,这是我们想要感谢的!我已经在使用count变量,仅在第二次调用实际加载iframe时触发iframeload代码。但我正在寻找一种更优雅、更惯用的解决方案,而不需要这种老套的解决方法:@drake035我的示例仅使用count数据成员来显示DOM中的计数。它实际运行的方式是在将iframe添加到DOM后,使用Vue更新的生命周期挂钩设置一个标志。如果未设置该标志,则跳过函数调用。这意味着只有在将iframe添加到DOM后才会调用该函数,这通常会触发第一个侦听器。然后,当隐藏帧时,相同的生命周期钩子再次将标志设置为false。基本上,在没有计数的情况下,它们也会起同样的作用;这仅用于显示目的。@drake035我已清理了我的答案,并删除了count变量以使其更清晰一些。谢谢,但iframeLoaded仍会触发两次。。