Javascript 如何在Vue中渲染iframe中的子组件?
因此,我想向用户展示电子邮件发送前的预览。为了避免样式从父页面泄漏到预览中,我决定使用iframe。我希望预览在用户输入表单详细信息时实时更新 如何在iframe中呈现组件,以便在父窗体更新时其道具自动更新?这是我目前掌握的代码: 这是html: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="
<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属性中。由于某些原因,正在文档外部呈现组件。。。。