javascript - Vue2 中的条件 Prop

标签 javascript vuejs2 vue-component

我有一个用例,我可能需要将对象 props 作为 props 传递给子组件。

最初,我在一个组件中包含一个表单和一个表格。此表单将接受输入,将执行异步请求并呈现表格以供用户进行选择。然后用户可以点击一个按钮并隐藏表格并恢复表格以便重新输入参数。由于表单的内容取决于其父级的状态,因此最后的搜索参数仍在表单中。

当我重构组件以创建父组件的表单和表格子组件时,问题就出现了。现在表单将 $emit 事件给它的父级,它会执行异步操作并将结果作为 props 传递给表。这工作正常,但是当用户点击“返回表单”按钮时,表单会重新呈现,从而将其状态重置为初始值。

我尝试将表单的内容存储在父级中并将其作为 props 传递回表单,但这导致了初始设置值的问题。我不想直接改变 Prop ,所以我尝试了这种方法:

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>

表单组件.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

然后我尝试使用三元来使用 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 :''
    }

  }
},

但这会引发错误,指出 selectedAddress 未在实例上定义,但在渲染期间被引用。我猜这意味着使用三元来初始化 Prop 是错误的。

然后我尝试检查 mounted(){} 生命周期 Hook 中的 props 并在那里设置数据属性,如下所示:

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 生命周期 Hook 期间。无论如何,这种方法感觉很“hacky”。​​

我不太确定从这里到哪里去。如果重新挂载表单,我可以将表单数据提交到商店并再次获取它,但我不认为提交只应在其父级挂载时存在的内容是正确的方法。

谁能指导我使用更 Vue 的方法来实现这一目标?

最佳答案

我认为您应该能够通过将 FormComponent 中的代码从数据转移到计算来解决这个问题。
计算属性是 react 性的,所以当 initialValues 属性最终获得一些数据时,表单应该反射(reflect)它。
如果 initialValues 始终具有 address1、address2 等结构(即使它们最初为空),则 Object.assign 将起作用。如果不是(即 initialValues initially = {},您将必须逐个进行属性检查。

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

要为下一轮保留表单值,您需要通过 emit 向上传递 selectedAddress 并将它们应用于父 formValues。

我非常喜欢的一个替代方案是 Vuex,其中表单从商店获取初始值并通过一个 Action 回传到商店,这会启动异步工作并用结果更新商店。本质上,您的 displayResults 方法变成了操作,但您不需要 async..await。

Vuex 形式化了数据流模式,因此您可以更轻松地对其进行推理和调试。本质上,您不必担心将数据传入 props 并通过 emits 传出。

另一个想法,您可以通过在 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>

关于javascript - Vue2 中的条件 Prop ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46377169/

相关文章:

javascript - 将 Vue 查询参数从当前路由传递到 router-link

javascript - Angular.js 'Unknown provider: iProvider <- i' 生产错误

javascript - 相当于 jQuery .live() 的 Dojo 是什么?

javascript - 无法在链接内插入 vue-router 标签

javascript - 通过 JS 与视口(viewport)(非相对)相关的元素的位置坐标

javascript - 禁用提交 btn 时,预填充的表单输入元素不接受第一个输入

javascript - 在 .trigger 中使用冒号在 jQuery 中意味着什么?

javascript - 如何在 Vue JS 应用程序中单击按钮后将其更改为禁用

javascript - AWS 使用 Vue 扩大模块化导入

javascript - 我如何在 vuejs 中编写一些 php 代码