【问题标题】:Render Component in iframe using vuejs without src attribute使用没有 src 属性的 vuejs 在 iframe 中渲染组件
【发布时间】:2024-12-29 14:30:02
【问题描述】:
<iframe id="frame" width="100%" height="100%">

</ifrme>

我想在这个 iframe 中渲染组件。是否有在 iframe 中创建 html 元素或渲染组件的选项?

new Vue({
   el:'#frame',
   store:store,
   router:router,
   render: component
})

【问题讨论】:

    标签: html iframe vue.js


    【解决方案1】:

    您可以参考下面的链接,这对我帮助很大。 这是链接和代码sn-ps。

    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/

    【讨论】:

    • 一开始我并不清楚的是,Linusborg 的链接示例在他的模板中没有使用真正的
    • 这可行,但是如何将 CSS 加载到 iframe 中。我试图避免在 iframe 中发出 css 请求,是否有任何选项可以嵌入到样式中?
    • 是的,我们需要知道如何将 CSS 放入 iframe :)
    • 知道如何在文件组件中执行此操作吗?
    【解决方案2】:
    new Vue({
    el:'#frame',
    store:store,
    router:router,
    render: component
    })
    

    只需尝试为您的路线视图命名。 希望有效

    【讨论】:

      【解决方案3】:

      我试过了,还没有找到直接在#iframe上挂载vue的方法。

      不过,您可以将 div 添加到 #iframe 并挂载到该位置:

      // 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)
      })
      

      结果:

      <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>
      

      附:我在 chrome 扩展内容脚本 中使用了这段代码(javascript 注入页面)。如果你要使用 在别处确保不要破坏Same-origin policy

      【讨论】:

      • 我有同样的用例。创建 iframe 并在其中渲染 Vue 组件。虽然不应用组件的样式。您对此有什么建议吗?
      • var extStyle = document.createElement('link'); extStyle.rel = '样式表'; extStyle.href = browser.extension.getURL("somestyle.css"); iframe.contentWindow.document.head.appendChild(extStyle);
      • @nteath 你解决过这个问题吗?具有完全相同的用例。使用 Vue CLI,开发服务器/热重载将
      • 如果容器是完整的文档? &lt;html&gt;...&lt;/html&gt;
      【解决方案4】:

      对我来说最简单的方法是使用srcdoc 属性。它加载原始 html 覆盖 src 属性。

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

      更新:更详细的示例:考虑用户 html 输入的文本区域并希望在 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>
      

      【讨论】:

      • 这太完美了!非常简单,不使用不必要且复杂的抽象层。
      • 我希望这有更多的解释,以及相关的 javascript 代码。我认为"html" 代表应该由 vue 以某种方式提供的 html 片段?
      • @abulka 我用更详细的例子更新了我的答案,希望你能理解。 codesandbox.io/s/musing-haze-c0ydz?file=/src/App.vue
      最近更新 更多