16
<iframe id="frame" width="100%" height="100%">

</ifrme>

I want to render component in this iframe. Is there any option of creating html element or rendering component in iframe?

new Vue({
   el:'#frame',
   store:store,
   router:router,
   render: component
})
Mikhail_Sam
  • 10,602
  • 11
  • 66
  • 102
Vishal Dodiya
  • 399
  • 1
  • 3
  • 15

4 Answers4

17

The easiest way for me is to use srcdoc attribute. It loads raw html overriding src attribute.

<template>
    <iframe :srcdoc="html"></iframe>
</template>

Update: More detail example: Consider a textarea for a user html input and want to display in an iframe.


<template>
  <div id="app">
    <textarea v-model="html"></textarea>
    <iframe :srcdoc="html"></iframe>
  </div>
</template>

<script>
export default {
  name: "App",
  data(){
    return {
      html:"<h1>Hello I am H1 block</h1>"
    }
  }
};
</script>
Bedram Tamang
  • 3,748
  • 31
  • 27
  • This is perfect! Dead simple, and doesn't use unnecessary and complicating layers of abstraction. – Kevin Foster Mar 18 '21 at 23:30
  • I wish this had some more explanation, as well as the associated javascript code. I think `"html"` stands for a html fragment that is supposed to be supplied by vue somehow? – abulka Jun 16 '21 at 08:08
  • @abulka I updated my answer with more detail example, hope you understand. https://codesandbox.io/s/musing-haze-c0ydz?file=/src/App.vue – Bedram Tamang Nov 12 '21 at 06:22
12

You can refer below link That helped me a lot. Here is the link and the code snippets.

Vue.component('i-frame', {
  render(h) {
    return  h('iframe', {
      on: { load: this.renderChildren }
    })
  },
  beforeUpdate() {
    //freezing to prevent unnessessary Reactifiation of vNodes
    this.iApp.children = Object.freeze(this.$slots.default)
  },  
  methods: {
    renderChildren() {
      const children = this.$slots.default
      const body = this.$el.contentDocument.body      
      const el = document.createElement('DIV') // we will mount or nested app to this element
      body.appendChild(el)
      
      const iApp = new Vue({
        name: 'iApp',
        //freezing to prevent unnessessary Reactifiation of vNodes
        data: { children: Object.freeze(children) }, 
        render(h) {
          return h('div', this.children)
        },
      })
      
      iApp.$mount(el) // mount into iframe
      
      this.iApp = iApp // cache instance for later updates
      
      
    }
  }
})

Vue.component('test-child', {
  template: `<div>
  <h3>{{ title }}</h3>
  <p>
  <slot/>
  </p>
  </div>`,
  props: ['title'],
  methods: {
    log:  _.debounce(function() {
      console.log('resize!')
    }, 200)
  },
  mounted() {
    this.$nextTick(() => {
      const doc = this.$el.ownerDocument
      const win = doc.defaultView
      win.addEventListener('resize', this.log)
    })
  },
  beforeDestroy() {
    const doc = this.$el.ownerDocument
    const win = doc.defaultView
    win.removeEventListener('resize', this.log)
  }  
})

new Vue({
  el: '#app',
  data: {
    dynamicPart: 'InputContent',
    show: false,
  }
})

https://jsfiddle.net/Linusborg/ohznser9/

Pierre Lezan
  • 120
  • 1
  • 10
Vishal Dodiya
  • 399
  • 1
  • 3
  • 15
  • 2
    Something that was not immediately clear to me at first is that the linked example by Linusborg does not use a real – William Apr 26 '17 at 19:06
  • This works, but how to load CSS into the iframe. I'm trying to avoid making an css request in the iframe, any options to embed to style? – Marcel Van de Weerd Jun 16 '17 at 21:33
  • ye, we need to know how put CSS into iframe :) – Guarana Jul 03 '20 at 20:14
  • 1
    any idea of hoW to do this in file components? – Ali Mar 11 '21 at 16:51
  • https://forum.vuejs.org/t/render-inside-iframe/6419 (Original thread of LinusBorgs fiddle) – Shaya Ulman Apr 30 '22 at 19:49
2

I've tried and haven't found a way to mount vue directly on #iframe.

Yet, you can add div to #iframe and mount to that:

// create iframe element
var iframe = document.createElement('iframe')
iframe.id = 'iframe'
// place iframe inside page html
document.documentElement.insertBefore(iframe, document.querySelector('html').firstChild)

// append div to iframe
var container = document.createElement('div')
container.id = 'container'
iframe.contentWindow.document.body.appendChild(container)

// render vue component inside iframe on #container
new Vue({
el: container,
render: h => h(component)
})

Result:

<html>
  <iframe id="iframe">
    #document
    <html>
      <head>
      </head>
      <body><!-- <-- here was <div id="container"></div> -->
        <div class="message" style="color: orange;">Hello from Vue component!</div>
      </body>
    </html>
  </iframe>
  <head>
  </head>
  <body>
  </body>
</html>

P.s. I've used this code in chrome extension content scripts (javascript injected into pages). If you're going to use it elsewhere make sure not to break Same-origin policy.

  • I 'm having the same use case. Created the iframe and rendered the Vue components inside. The styles of the components are not applied though. Do you have any recommendations for this ? – nteath Jun 19 '20 at 10:23
  • var extStyle = document.createElement('link'); extStyle.rel = 'stylesheet'; extStyle.href = browser.extension.getURL("somestyle.css"); iframe.contentWindow.document.head.appendChild(extStyle); – Mike O.O. Oct 25 '20 at 16:30
  • 1
    @nteath did you ever solve this ? Have exactly the same use case.Using the Vue CLI, the dev server/hot reload injects – Matt Bryson Nov 12 '20 at 19:03
  • if container is a full document? `...` – 山茶树和葡萄树 Jul 27 '21 at 07:31
0
new Vue({
el:'#frame',
store:store,
router:router,
render: component
})

just try to give a name to your route view. Hope it works

Tarang Dave
  • 331
  • 2
  • 11