使用VueJS和VuetifyJS生成输入字段并动态保存输入的值

问题描述

我正在尝试生成一些输入文本字段(v-text-field)并渲染它们,直到现在为止都可以正常工作。

参考JSON

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <Meta charset="utf-8">
    <title></title>
    
    <link rel="stylesheet" type="text/css" href="https://ws1.postescanada-canadapost.ca/css/addresscomplete-2.30.min.css?key=tr28-mh11-ud79-br91" />
    <script type="text/javascript" src="https://ws1.postescanada-canadapost.ca/js/addresscomplete-2.30.js?key=tr28-mh11-ud79-br91&app=14466&culture=en"></script>
  </head>
  <body>
    <div class="input-line">
      <input id="search" type="text" name="" value="">
    </div>
    <div class="input-line">  
        <label for="street-address">Address</label>  
        <input id="street-address" type="text" placeholder="Street address" autofocus /> 
    </div> 
    <div class="input-line">  
        <label for="street-address2"></label>  
        <input id="street-address2" type="text" placeholder="" /> 
    </div> 
    <div class="input-line">  
        <label for="city"></label>  
        <input id="city" type="text" placeholder="City" /> 
    </div> 
    <div class="input-line">  
        <label for="state"></label>  
        <input id="state" type="text" placeholder="State/Province" /> 
    </div> 
    <div class="input-line">  
        <label for="postcode"></label>  
        <input id="postcode" type="text" placeholder="Zip/Postcode" /> 
    </div> 
    <div class="input-line">  
        <label for="country"></label>  
        <input id="country" type="text" placeholder="Country" /> 
    </div>  
     
    <div class="input-line">  
        <label for="multi-unit"></label>  
        <input id="multi-unit" type="text" placeholder="Multi-Unit-Indicator" /> 
    </div> 
    <div class="input-line">  
        <label for="residential-business"></label>  
        <input id="residential-business" type="text" placeholder="Residential/Business" /> 
    </div> 
  </body>
  
  <script type="text/javascript">  
    var fields = [   
        { element: "search",field: "",mode: pca.fieldMode.SEARCH },{ element: "street-address",field: "Line1",mode: pca.fieldMode.POPULATE },{ element: "street-address2",field: "Line2",{ element: "city",field: "City",{ element: "state",field: "ProvinceName",{ element: "postcode",field: "PostalCode" },{ element: "country",field: "CountryName",mode: pca.fieldMode.COUNTRY },{ element: "multi-unit",field: "{AcMua}",{ element: "residential-business",field: "{AcRbdi}",mode: pca.fieldMode.POPULATE }  
    ],options = {   
        key: "ADD-YOUR-KEY-HERE"  
    },control = new pca.Address(fields,options); 
</script>
  
  
</html>

当我尝试按以下方式在模板上呈现文本输入时;

{
  "documentAttributes" : {
    "documentNumber" : "textField","issueDate" : "dateField","issuingAuthority" : "textField","dynamicProperties" : {
      "recordedCityOfIssue" : "textField","recordedStateOrProvinceOfIssue" : "textField","recordedPaperNumber" : "textField","recordedFamilyNumber" : "textField","recordedOrderNumber" : "textField","issueRecordNumber" : "textField"
    }
  },"personalAttributes" : {
    "socialNumber" : "textField","surname" : "textField","name" : "textField","paternalName" : "textField","maternalName" : "textField","placeOfBirth" : "textField","dateOfBirth" : "dateField","maritalStatus" : "textField","gender" : "textField"
  }
}

我创建了一个数组来保存模板渲染中动态生成的文本字段中的类型化值,但是只要我在该字段上键入任何内容,只要所有文本字段都具有相同的值,我就无法实现。

<v-expansion-panel>
  <v-expansion-panel-header>Document Attributes</v-expansion-panel-header>
  <v-expansion-panel-content
    v-for="(value,name,index) in refJSON"
    :key="name"
  >
    <v-text-field
      :label="name"
      :placeholder="name"
      :id="index"
      :value="name"
      v-model="docAttributesExtractionResult[index].name"
    />   
  </v-expansion-panel-content>
</v-expansion-panel>

我基本上是想在docAttributesExtractionResult数组上实现以下结果

data: () => ({
  docAttributesExtractionResult: [{},{},{}],}),

有人对在阵列上正确绑定v模型实现这一点有任何线索吗?

一个小提琴的例子,我正在尝试做同样的事,但未能成功。

https://jsfiddle.net/6zhLdrpm/

解决方法

我认为您的问题与Vuetify无关。
与之类似,将BootstrapVue或Vue与纯HTML输入一起使用时,您将遇到相同的确切问题。实际上,它与Vue几乎没有关系,因为在其他任何使用输入元素绑定的库中,您都会遇到相同的问题。


首先,:valuev-model不兼容。您可以使用其中一个。 :value设置安装组件时的值,而v-model提供2路数据绑定。您显然想要v-model

然后,您想从包含项目或项目集合的任意结构创建动态表单。
这可以使用递归组件来解决(如果当前节点不是集合,则呈现输入;如果节点是集合,则使用v-for递归组件)。虽然该模型可以正常工作,但它达到了很高的复杂度,这使调试变得很麻烦。对于少于3个级别的递归,这是不值得的,IHMO。

这是解决案件的实用方法:

Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
  el: '#app',data: () => ({
    refJSON: jsonData(),extraction: nullify(jsonData())
  }),methods: {
    getInputType(type) {
      return type.replace('Field','')
    }
  }
})

function nullify(obj) {
  for (const prop in obj) {
    obj[prop] = typeof obj[prop] === 'object' ?
      nullify(obj[prop]) :
      null
  }
  return obj;
}

function jsonData() {
  return {
    "documentAttributes": {
      "documentNumber": "textField","issueDate": "dateField","issuingAuthority": "textField","dynamicProperties": {
        "recordedCityOfIssue": "textField","recordedStateOrProvinceOfIssue": "textField","recordedPaperNumber": "textField","recordedFamilyNumber": "textField","recordedOrderNumber": "textField","issueRecordNumber": "textField"
      }
    },"personalAttributes": {
      "socialNumber": "textField","surname": "textField","name": "textField","paternalName": "textField","maternalName": "textField","placeOfBirth": "textField","dateOfBirth": "dateField","maritalStatus": "textField","gender": "textField"
    }
  }
}
label {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
input {
  margin-left: .5rem;
}
  #app {
    display: flex;
    flex-direction: row-reverse;
    justify-content: space-between;
    flex-wrap: wrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<div id="app">
  <div v-for="(a,b) in refJSON" :key="b">
    <div v-for="(c,d) in a">
      <label v-if="typeof c === 'string'">
        <pre>{{`${b}.${d}`}}</pre>
        <input  v-model="extraction[b][d]" :type="getInputType(c)" />
      </label>
      <div v-else>
        <label v-for="(e,f) in c">
          <pre>{{`${b}.${d}.${f}`}}</pre>
          <input v-model="extraction[b][d][f]" :type="getInputType(e)" />
        </label>
      </div>
    </div>
  </div>
  <pre v-html="extraction" />
</div>

nullify函数提供了模型结构(来自JSON源)。显然,您可以对其进行调整/改进以提供基于类型的默认值。