Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在Vue中渲染iframe中的子组件?_Javascript_Vue.js_Iframe - Fatal编程技术网

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

Javascript 如何在Vue中渲染iframe中的子组件?,javascript,vue.js,iframe,Javascript,Vue.js,Iframe,因此,我想向用户展示电子邮件发送前的预览。为了避免样式从父页面泄漏到预览中,我决定使用iframe。我希望预览在用户输入表单详细信息时实时更新 如何在iframe中呈现组件,以便在父窗体更新时其道具自动更新?这是我目前掌握的代码: 这是html: <template> <div id="confirmation"> <h2>Give a gift</h2> <form @submit.prevent="

因此,我想向用户展示电子邮件发送前的预览。为了避免样式从父页面泄漏到预览中,我决定使用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>

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

因此,正如其中一条评论所述,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
        }
    }
}
最后,以下是如何将数据从确认组件传递到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)
        }
    }
}
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
        }
    }
}
最后是实际预览组件:

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)
        }
    }
}
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
        }
    }
}
从“../../../templates/styles”导入样式
导出默认值{
名称:“PreviewComponent”,
安装的(){
此.$store.commit('stylesChange',styles)
},
计算:{
赎回(网址){
返回`${window.config.stitcher\u网站}/gift?代码=`
},
自定义_消息(){
if(this.form.message){
设div=document.createElement('div')
div.innerHTML=this.form.message
设text=div.textContent | | div.innerText |“”
返回文本。替换(/(?:\r\n |\r |\n)/g,“
”) } 返回空 }, 表格({ 返回此。$store.state.form }, 术语(){ 返回此项。$store.state.term }, senderEmail(){ 返回此邮件。$store.state.senderEmail } } }

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

因此,正如其中一条评论所述,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
        }
    }
}
最后,以下是如何将数据从确认组件传递到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)
        }
    }
}
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
        }
    }
}
最后是实际预览组件:

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)
        }
    }
}
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
        }
    }
}
从“../../../templates/styles”导入样式
导出默认值{
名称:“PreviewComponent”,
安装的(){
此.$store.commit('stylesChange',styles)
},
计算:{
赎回(网址){
返回`${window.config.stitcher\u网站}/gift?代码=`
},
自定义_消息(){
if(this.form.message){
设div=document.createElement('div')
div.innerHTML=this.form.message
设text=div.textContent | | div.innerText |“”
返回文本。替换(/(?:\r\n |\r |\n)/g,“
”) } 返回空 }, 表格({ 返回此。$store.state.form }, 术语(){ 返回此项。$store.state.term }, senderEmail(){ 返回此邮件。$store.state.senderEmail } } }

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

如果使用vuex,这很容易。数据将实时更新,您可以访问整个页面的数据,您只需在必要时显示和隐藏
预览组件即可。哦,明白了。在iframe中是否可以访问父页面中的vuex数据?如果这是可能的话,它似乎可以工作。由于我让vuex正常工作,现在的问题似乎是将组件html和样式放入iframes#document属性中。由于某些原因,组件在文档外部呈现……如果使用vuex,这很容易。数据将实时更新,您可以访问整个页面的数据,您只需在必要时显示和隐藏
预览组件即可。哦,明白了。在iframe中是否可以访问父页面中的vuex数据?如果这是可能的话,它似乎可以工作。由于我让vuex正常工作,现在的问题似乎是将组件html和样式放入iframes#document属性中。由于某些原因,正在文档外部呈现组件。。。。