使用 Vue js 发布具有多个组件的表单的最佳方式是啥

Posted

技术标签:

【中文标题】使用 Vue js 发布具有多个组件的表单的最佳方式是啥【英文标题】:What is the best way to post form with multiple components using Vue js使用 Vue js 发布具有多个组件的表单的最佳方式是什么 【发布时间】:2019-01-11 09:28:51 【问题描述】:

当我在我的 Vue 大礼包中(最近开始但到目前为止我真的很喜欢学习这个框架)时,出现了几个问题。其中之一是如何从多个组件发布表单。因此,在我继续前进之前,我想问一下您对这种结构方式有何看法,如果我错了,请指出正确的方向。

来了。 我正在使用 ASP.NET CORE 2.1 和 Vue JS 模板(使用 webpack)(https://github.com/MarkPieszak/aspnetcore-Vue-starter)开发一个 SPA 项目,我的项目在多个容器中构建,如下所示: 在我的 app-root 中,我注册了几个容器

<template>

  <div id="app" class="container">

    <app-first-container></app-first-container>
    <app-second-container></app-second-container>
    <!--<app-third-container></app-third-container>-->
    <app-calculate-container></app-calculate-container>
    <app-result-container></app-result-container>

  </div>   
</template>

<script>
  // imported templates
  import firstContainer from './first-container'
  import secondContainer from './second-container'
  import calculateContainer from './calculateButton-container'
  //import thirdContainer from './third-container'
  import resultContainer from './result-container'

  export default 
    components: 
      'app-first-container': firstContainer,
      'app-second-container': secondContainer,
     // 'app-third-container': thirdContainer,
      'app-calculate-container': calculateContainer,
      'app-result-container': resultContainer
    
   
</script>

在我的第一个容器中,我的脚本文件有几个下拉菜单和两个输入字段,我从 API 获取数据并使用获取的数据填充下拉菜单和输入字段。

类似这样的东西(输入一些虚拟代码进行演示)

<template>
  <div>
    <h1>Crops table</h1>

    <p>This component demonstrates fetching data from the server. dataMessage</p>

    <div class="form-row">

      <div class="form-group col-md-6">
        <label  for="exampleFormControlSelect1" class="col-form-label-sm font-weight-bold">1. Some text</label>
        <select class="form-control" id="exampleFormControlSelect1" v-model="pickedCropType" @change="getCropsByType()">
          <option v-for="(cropType, index) in cropTypes" :key="index" :value="cropType.id" :data-imagesrc="cropType.imgPath"> cropType.name </option>
        </select>
      </div>

      <div class="form-group col-md-6">
        <label for="exampleFormControlSelect2" class="col-form-label-sm font-weight-bold">2. Some text</label>
        <select class="form-control" id="exampleFormControlSelect2">
          <option v-for="(crop, index) in cropSelectList" :key="index" :value="crop.id"> crop.name </option>
        </select>
      </div>
    </div>

  </div>
</template>

<script>

  import  mapActions, mapState  from 'vuex'

  export default 
    data() 
      return 
        cropTypes: null,
        cropSelectList: null,
        crops: null,
        pickedCropType: null,

      
    ,

    methods: 
      loadPage: async function () 
        try 
          //Get crop types and create a new array with crop types with an added imgPath property
          var cropTypesFinal = [];
          let responseCropTypes = await this.$http.get(`http://localhost:8006/api/someData`);
          responseCropTypes.data.data.forEach(function (element) 

            cropTypesFinal.push(tmpType);
          );


         catch (err) 
          window.alert(err)
          console.log(err)
        
      ,
      getCropsByType: async function () 
        //Get crops by crop type
        let responseCrops = await this.$http.get(`http://localhost:8006/api/crop/Type/$this.pickedCropType`);
        var responseCropsData = responseCrops.data.data;
        this.cropSelectList = responseCropsData;
      
    ,

    async created() 
      this.loadPage()
    
  
</script>

在我的第二个容器中,我有不同的下拉菜单和具有不同脚本等的不同输入字段。

所以,我的问题是:

1.) 我在第一个容器和第二个容器中有必需的数据表单字段我有额外的数据,我的提交按钮在第三个容器中分开(app-result-container) .那么,如果不是这种构建容器的正确且合乎逻辑的方式,您能否指出正确的方向?

2.) 在我正在处理/获取/提交特定容器的某些数据的每个容器中输入脚本标记是否明智?我是否应该将脚本标签放在单独的文件中并保持结构干净,将 html 与 js 文件分开。

示例: 从“某事”导入某事

export default 
  data () 
    return 
      someData: 'Hello'
    
  ,
  methods: 
    consoleLogData: function (event) 
      Console.log(this.someData)
    
  

3.) 我可以将输入值从一个容器发送到另一个容器(在我的特定情况下,从第一个和第二个容器到 app-calculate-container(第三个容器))吗?

如何使用计算的导入值提交返回结果容器

【问题讨论】:

【参考方案1】:

如果您希望组件相互通信或共享数据,您将需要 emit 将一个组件从一个组件向上传递到父组件并通过 props 将其向下传递,或者使用某种状态管理模型,例如Vuex,你的每个组件都可以监听 store。

看看这个代码沙箱:https://codesandbox.io/s/8144oy7xy2

App.vue

<template>
  <div id="app">
    <child-input @input="updateName" />
    <child-output :value="name" />
  </div>
</template>

<script>
import ChildInput from "@/components/ChildInput.vue";
import ChildOutput from "@/components/ChildOutput.vue";

export default 
  name: "App",
  components: 
    ChildInput,
    ChildOutput
  ,
  data() 
    return 
      name: ""
    ;
  ,
  methods: 
    updateName(e) 
      this.name = e.target.value;
    
  
;
</script>

ChildInput.vue

<template>
  <input type="text" @input="changeHandler">
</template>

<script>
export default 
  name: "ChildInput",
  methods: 
    changeHandler(e) 
      this.$emit("input", e);
    
  
;
</script>

ChildOutput.vue

<template>
  <p> value </p>
</template>

<script>
export default 
  name: "ChildOutput",
  props: 
    value: 
      type: String,
      default: ""
    
  
;
</script>

发生了什么事?

ChildInput 组件是一个文本字段,在其中的每次更改时都会触发一个事件(使用this.$emit() 发出并传递整个事件向上)。

当此事件触发时,App 正在侦听更改,这会触发更新名称数据属性的方法。

因为name 是一个响应式数据属性,并且作为道具传递给ChildOutput 组件,所以屏幕会重新渲染并使用写入的文本进行更新。

ChildInputChildOutput 都不知道彼此。它是监听传递给它的事件的父级,然后传递新的道具。

这种工作方式很好且易于理解,但我强烈建议您查看 Vuex,因为当您超出琐碎的任务时,这种方法可能会变得混乱和复杂。

【讨论】:

感谢您的详细回答。我会尝试用你的解释来弄清楚。我确实有一个问题,我的“构建应用程序”的方式是正确的还是应该使用一些不同的方法? 我不确定是否有真正正确的方法......但我总是使用 Vue Cli 来建立一个新项目,我发现这是一个很好的起点。你试过了吗? cli.vuejs.org 感谢您的指点和指示 :) 事实上我确实尝试过,我必须说我非常喜欢它:) 好东西,对我帮助很大。 多输入怎么样。让我们举一个 AddressInputs 组件的例子(它有很少的预设计输入)。如何将该数据发送到名为 CompanyRegForm 的父组件?我们可以在聊天中讨论。

以上是关于使用 Vue js 发布具有多个组件的表单的最佳方式是啥的主要内容,如果未能解决你的问题,请参考以下文章

跨页面重用相同组件(具有相同道具)的最佳方法

如何将初始表单值传递给 Vue.js 中的子组件?

Vue.js - 具有复杂子项的单元测试组件

Vue:通过方法从父组件提交子组件表单的最佳方式

带有子表单的Vue模态对话框,提交数据

不能使用 Vue JS 作为 CDN 的 3rd 方组件