Joe*_*yss 6 javascript vue-component vuejs2
我有一个用例,我可能需要将一个对象props作为道具传递给子组件.
最初,我有一个组件中包含的表单和表.该表单将接受输入,将执行异步请求,并且将呈现该表以供用户进行选择.然后,用户可以点击按钮并隐藏表格并重新启动表格,以便重新输入参数.由于表单的内容取决于其父级的状态,因此最后的搜索参数仍然在表单中.
当我重构组件以同时创建父组件的表单子组件和表子组件时,就出现了这个问题.现在,表单将$emit事件发送到其父级,它将执行异步操作并将结果传递props给表.这工作正常,但是当用户点击"返回到表单"按钮时,表单将被重新呈现,从而将其状态重置为初始值.
我尝试将表单的内容存储在父表单中并将其传递回表单,props但这导致了初始设置值的问题.我不想直接改变道具,所以我尝试了这种方法:
<template>
<div v-if="formShown">
<form-component :initialValues="formValues" @formSubmitted="displayResults"></form-component>
</div>
<div v-if="tableShown">
<table-component :results="fetchedResults" @returnToForm="returnToForm"></table-component>
</div>
</template>
<script>
export default {
data(){
return{
formShown: true,
tableShown: false,
formValues:{
address1: '',
address2: '',
address3: '',
country: ''
},
fetchedResults: []
}
},
methods:{
async displayResults(){
this.fetchedResults = await someAsynchronousCall();
this.formShown = false;
this.tableShown = true;
},
returnToForm(){
this.tableShown = false;
this.formShown = true;
}
}
}
</script>
Run Code Online (Sandbox Code Playgroud)
<template>
<!--Some form fields here, bound to data(){}, ommitted for brevity-->
</template>
<script>
export default{
props:['initialValues'],
data(){
return{
//Original structure
/*selectedAddress:{
address1: '',
address2: '',
address3: '',
country: ''
}*/
selectedAddress: JSON.parse(JSON.stringify(this.initialValues)) //Object.assign({}, this.initialValues) //tried both of these for deep copy
}
}
}
</script>
Run Code Online (Sandbox Code Playgroud)
这个问题是,当最初创建组件时,它会被传递一个空对象(或者更确切地说是一个只有空属性的对象,我认为它们相同的东西),这意味着我的数据属性被初始化为undefined.
然后我尝试使用三元素来使用props中的值或空字符串初始化数据对象,如下所示:
data(){
return{
selectedAddress: {
address1: this.initialValues.address1 ? this.initialValues.address1 :'',
address2: this.initialValues.address2 ? this.initialValues.address2 :'',
address3: this.initialValues.address3 ? this.initialValues.address3 :'',
country:this.initialValues.country ? this.initialValues.country :''
}
}
},
Run Code Online (Sandbox Code Playgroud)
但是这会抛出错误,说明selectedAddress没有在实例上定义但在渲染期间引用.我猜这意味着使用三元来初始化道具是错误的.
然后我尝试在mounted(){}生命周期钩子中检查道具并在那里设置数据属性,如下所示:
mounted(){
if(!this.initialValues || _.isEmpty(this.initialValues)){
Logger.info(`no props passed, no setup needed`);
return;
}
if(this.initalValues.address1){
Logger.info(`setting address 1`);
this.selectedAddress.address1 = this.initalValues.address1;
}
if(this.initialValues.address2){
Logger.info(`setting address 2`);
this.selectedAddress.address2 = this.initalValues.address2;
}
if(this.initialValues.address3){
Logger.info(`setting address 3`);
this.selectedAddress.address3 = this.initalValues.address2;
}
if(this.initialValues.country){
Logger.info(`setting country`);
this.selectedAddress.country = this.initalValues.country;
}
}
Run Code Online (Sandbox Code Playgroud)
这适用于表单的第一次运行,但this.initialValues始终undefined在安装组件时.我已经检查了组件状态并发现initialValues确实存在,只是在mounted生命周期钩子期间没有.无论如何,这种方法感觉"hacky".
我不确定从哪里开始.我可以将表单数据提交到商店并在表单重新安装时再次获取它,但我不想提交一些只应在其父服务器安装时才存在的东西是正确的方法.
任何人都可以指导我采用更Vue的方式实现这一目标吗?
我认为您应该能够通过将 FormComponent 中的代码从数据转移到计算来解决这个问题。
计算属性是反应性的,因此当initialValues属性最终获取一些数据时,表单应该反映它。
如果initialValues 始终具有address1、address2 等结构(即使它们最初为空),则Object.assign 将起作用。如果不是(即,initialValues 最初 = {},您将必须逐个属性进行检查。
<template>
<!--Some form fields here, bound to data(){}, ommitted for brevity-->
<div>selectedAddress.address1</div>
<div>selectedAddress.address2</div>
</template>
<script>
export default{
props:['initialValues'],
data(){
},
computed: {
selectedAddress() {
return Object.assign({}, this.initialValues)
}
}
}
</script>
Run Code Online (Sandbox Code Playgroud)
要保留下一轮的表单值,您需要通过发射向上传递 selectedAddress 并将它们应用到父 formValues。
我非常喜欢的另一种选择是 Vuex,其中表单从存储中获取初始值,并通过操作发回存储,从而启动异步工作并用结果更新存储。本质上,您的 displayResults 方法成为操作,但您不需要 async..await。
Vuex 形式化了数据流模式,以便您可以更轻松地对其进行推理和调试。本质上,您不必担心将数据传入 props 并通过生成传出。
另一个想法是,您可以通过在 FormContainer 中使用 v-show 而不是 v-if 来避免重置 FormComponent 值。这应该保留表单 div (及其状态)但隐藏它。然后,您可能根本不需要在父级上使用 formValues 。
<template>
<div v-show="formShown">
<form-component :initialValues="formValues" @formSubmitted="displayResults"></form-component>
</div>
<div v-show="tableShown">
<table-component :results="fetchedResults" @returnToForm="returnToForm"></table-component>
</div>
</template>
Run Code Online (Sandbox Code Playgroud)