Vue2中的条件道具
我有一个用例,我可能需要将一个对象props
作为道具传递给子组件。Vue2中的条件道具
最初,我有一个组件中包含的表单和表。该表单将接受输入,将执行一个异步请求,并为该用户提供该表以供选择。然后用户可以按下一个按钮并隐藏表格,并将表格带回来,以便重新输入参数。由于表单的内容取决于其父项的状态,因此最后的搜索参数仍处于表单中。
当我重构组件以创建父窗体和表的子组件时,就会出现此问题。现在表单将$emit
事件发送给它的父项,它将执行异步操作并将结果作为props
传递给表。这工作得很好,但是当用户点击“返回到表单”按钮时,表单被重新呈现,从而将其状态重置为初始值。
我试图将表单的内容存储在父级中,并将其传回到表单props
,但导致初始设置值的问题。我不想直接发生变异的道具,所以我尝试这个办法:
FormContainer.vue
<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>
FormComponent.vue
<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>
这样做的问题是,当组件最初创建时,它正在传递一个空对象(或者更确切地说是一个只有空属性的对象,我假设它们是相同的东西),这意味着我的数据属性被初始化为undefined
。
然后我用三元初始化与道具的值或空字符串数据对象试过了,是这样的:
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 :''
}
}
},
但是,这将引发错误说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;
}
}
这适用于表单的第一次运行,但this.initialValues
总是undefined
当组件被安装。我检查了组件状态,发现initialValues
确实存在,只是在mounted
生命周期中没有挂钩。无论如何,这种方法都感觉到'黑客'。
我不确定该从哪里出发。我可以将表单数据提交给商店,如果表单重新装入,可以重新获取表单数据,但是我不想提交仅在父表单挂载时存在的东西才是正确的方法。
任何人都可以引导我更多Vue的方式来实现这一目标吗?
我认为你应该能够通过将FormComponent中的代码从数据移动到计算来进行排序。
计算属性是反应性的,所以当initialValues prop最终获得一些数据时,表单应该反映它。
如果initialValues始终具有address1,address2等结构(即使它们最初为null),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>
为了保持表格值下一轮需要通过发光以通过selectedAddress起来,并将其应用父类型值
我非常喜欢的一种替代方法是Vuex,表单从商店获取初始值并通过一个操作发布回商店,该操作启动异步工作并使用结果更新商店。本质上你的displayResults方法变成了动作,但你并不需要async..a等待。
Vuex正式将数据流模式,以便您可以更轻松地推理和调试。本质上,你不必担心将数据传递给道具并通过散发。
又一想,你能避免使用V-秀,而不是V-如果FormContainer重置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>
我目前使用的是Vuex,我实现的解决方法是使用Vuex。我的问题是,我必须确保记得在所有适当的时间,即当表单容器的父级从DOM中删除时,当用户重置表单时,记录分派正确的操作以从商店中删除数据从表单中,当用户从其父母等重置表单时,我可以看到这是一种简单的方法,在表单中有一个不正确的初始状态。 – JavaTheNutt
使用计算属性并不意味着如果在表单仍处于打开状态时,“initalValues”的内容发生了变化,那么表单字段值本身会发生变化?我试图使用Object.assign()来打破表单值和从父类传递的数据之间的链接,如果它在'computed(){}'中使用,情况仍然如此吗? – JavaTheNutt
我确实喜欢隐藏表单的想法,它会降低复杂性,并且它不是挂在DOM周围的一个巨大组件。我知道通常会接受的做法是移除未使用的元素,而不是隐藏它们,但在这种情况下,我可能会做出豁免 – JavaTheNutt