如何在Vue的iframe中渲染子组件?

因此,我想向用户显示电子邮件发送之前的预览。为了避免样式从父页面泄漏到预览中,我决定使用iframe。我希望在用户输入表单详细信息时实时更新预览。

我将如何在iframe中渲染组件,以便在更新父窗体时自动更新其道具?这是我到目前为止的代码:

这是html:

<template>
    <div id="confirmation">
        <h2>Give a gift</h2>
        <form @submit.prevent="checkout()">
            <div class="date-section">
                <label class="wide">Send</label>
                <input type="radio" name="sendLater" v-model="sendLater" required :value="false">
                <span>Now</span>
                <input type="radio" name="sendLater" v-model="sendLater" required :value="true">
                <span style="margin-right: 5px;">Later: </span>
                <date-picker :disabled="!sendLater" v-model="date" lang="en" />
            </div>
            <div>
                <label>Recipient Email</label>
                <input type="email" class="custom-text"  v-model="form.email" required>
            </div>
            <div>
                <label>Recipient Name</label>
                <input type="text" class="custom-text"  v-model="form.name" required>
            </div>
            <div>
                <label>Add a personal message</label>
                <textarea v-model="form.message" />
            </div>
            <p class="error" v-if="error">Please enter a valid date.</p>
            <div class="button-row">
                <button class="trumpet-button" type="submit">Next</button>
                <button class="trumpet-button gray ml10" type="button" @click="cancel()">Cancel</button>
            </div>
        </form>
        <iframe id="preview-frame">
            <preview-component :form="form" :sender-email="senderEmail" :term="term" />
        </iframe>
    </div>
</template>

这是js(注意:PreviewComponent是将在iframe中呈现的实际预览):

export default {
    name: 'ConfirmationComponent',components: {
        DatePicker,PreviewComponent
    },props: {
        term: {
            required: true,type: Object
        }
    },data() {
        return {
            form: {
                name: null,email: null,message: null,date: null
            },date: null,sendLater: false,error: false
        }
    },computed: {
        senderEmail() {
            // utils comes from a separate file called utils.js
            return utils.user.email || ''
        }
    },watch: {
        'form.name'(val) {
            this.renderIframe()
        },'form.email'(val) {
            this.renderIframe()
        }
    },methods: {
        renderIframe() {
            if (this.form.name != null && this.form.email != null) {
                console.log('rendering iframe')
                // not sure what to do here......
            }
        }        
    }
}

我已经尝试过各种方法,但是似乎最难的是正确设置预览组件的道具。大家能提供的任何帮助将不胜感激。

lxqcys 回答:如何在Vue的iframe中渲染子组件?

因此,如评论之一中所述,Vuex对此非常有效。

我还最终创建了一个自定义“ IFrame”组件,该组件将呈现iframe中其插槽内的所有内容。

这是我的Vuex商店:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store = new Vuex.Store({
    state: {
        form: {
            name: null,email: null,message: null
        },senderEmail: null,term: null,styles: null
    },mutations: {
        updateForm(state,form) {
            state.form = form
        },updateEmail(state,email) {
            state.senderEmail = email
        },updateTerm(state,term) {
            state.term = term
        },stylesChange(state,styles) {
            state.styles = styles
        }
    }
})

我的IFrame组件:

import Vue from 'vue'
import { store } from '../../store'

export default {
    name: 'IFrame',data() {
        return {
            iApp: null,}
    },computed: {
        styles() {
            return this.$store.state.styles
        }
    },render(h) {
        return h('iframe',{
            on: {
                load: this.renderChildren
            }
        })
    },watch: {
        styles(val) {
            const head = this.$el.contentDocument.head

            $(head).html(val)
        }
    },beforeUpdate() {
        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',store,data() {
                    return {
                        children: Object.freeze(children)
                    }
                },render(h) {
                    return h('div',this.children)
                }
            })

            iApp.$mount(el)

            this.iApp = iApp
        }
    }
}

最后,这是将数据从ConfirmationComponent传递到PreviewComponent的方式:

export default {
    name: 'ConfirmationComponent',mounted() {
        this.$store.commit('updateEmail',this.senderEmail)
        this.$store.commit('updateTerm',this.term)
    },watch: {
        'form.name'(val) {
            this.updateIframe()
        },'form.email'(val) {
            this.updateIframe()
        }
    },methods: {
        updateIframe() {
            this.$store.commit('updateForm',this.form)
        }
    }
}

最后是实际的PreviewComponent:

import styles from '../../../templates/styles'

export default {
    name: 'PreviewComponent',mounted() {
        this.$store.commit('stylesChange',styles)
    },computed: {
        redemption_url() {
            return `${window.config.stitcher_website}/gift?code=`
        },custom_message() {
            if (this.form.message) {
                let div = document.createElement('div')

                div.innerHTML = this.form.message

                let text = div.textContent || div.innerText || ''

                return text.replace(/(?:\r\n|\r|\n)/g,'<br>')
            }
            return null
        },form() {
            return this.$store.state.form
        },term() {
            return this.$store.state.term
        },senderEmail() {
            return this.$store.state.senderEmail
        }
    }
}

希望这会对某人有所帮助。

本文链接:https://www.f2er.com/3155147.html

大家都在问