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> 
+0

我目前使用的是Vuex,我实现的解决方法是使用Vuex。我的问题是,我必须确保记得在所有适当的时间,即当表单容器的父级从DOM中删除时,当用户重置表单时,记录分派正确的操作以从商店中删除数据从表单中,当用户从其父母等重置表单时,我可以看到这是一种简单的方法,在表单中有一个不正确的初始状态。 – JavaTheNutt

+0

使用计算属性并不意味着如果在表单仍处于打开状态时,“initalValues”的内容发生了变化,那么表单字段值本身会发生变化?我试图使用Object.assign()来打破表单值和从父类传递的数据之间的链接,如果它在'computed(){}'中使用,情况仍然如此吗? – JavaTheNutt

+0

我确实喜欢隐藏表单的想法,它会降低复杂性,并且它不是挂在DOM周围的一个巨大组件。我知道通常会接受的做法是移除未使用的元素,而不是隐藏它们,但在这种情况下,我可能会做出豁免 – JavaTheNutt