因此,我想向用户显示电子邮件发送之前的预览。为了避免样式从父页面泄漏到预览中,我决定使用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......
}
}
}
}
我已经尝试过各种方法,但是似乎最难的是正确设置预览组件的道具。大家能提供的任何帮助将不胜感激。
答案 0 :(得分:0)
因此,如评论之一中所述,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
}
}
}
希望这会对某人有所帮助。