使用 VueJS 和 VuetifyJS 动态生成输入字段并保存输入的值
Generating input fields and saving entered values dynamically with VueJS & VuetifyJS
我正在尝试生成一些输入文本字段 (v-text-field) 并渲染它们,直到此时它们都可以正常工作。
引用JSON
{
"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>
我创建了一个数组来保存模板呈现中动态生成的文本字段中键入的值,但我无法实现它,因为只要我在该字段上键入任何内容,所有文本字段都具有相同的值。
data: () => ({
docAttributesExtractionResult: [{}, {}, {}, {}],
}),
我主要是想在我的 docAttributesExtractionResult 数组上实现以下结果
docAttributesExtractionResult: [{"documentNumber":"typedValue"}, {"issueDate":"selectedDateValue",.... etc}
有没有人知道如何通过在数组上正确绑定 v-model 来实现这一点?
一个示例 fiddle,我正在尝试这样做但未能成功。
我认为你的问题与 Vuetify 无关。
与此类似,使用带有普通 HTML 输入的 BootstrapVue 或 Vue 时,您会遇到同样的问题。事实上,它与 Vue 几乎没有任何关系,因为在输入元素上使用两种方式绑定的任何其他库中都会遇到同样的问题。
首先,:value
和 v-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 来源)。显然,您可以 tweak/improve 它根据类型提供默认值。
我正在尝试生成一些输入文本字段 (v-text-field) 并渲染它们,直到此时它们都可以正常工作。
引用JSON
{
"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>
我创建了一个数组来保存模板呈现中动态生成的文本字段中键入的值,但我无法实现它,因为只要我在该字段上键入任何内容,所有文本字段都具有相同的值。
data: () => ({
docAttributesExtractionResult: [{}, {}, {}, {}],
}),
我主要是想在我的 docAttributesExtractionResult 数组上实现以下结果
docAttributesExtractionResult: [{"documentNumber":"typedValue"}, {"issueDate":"selectedDateValue",.... etc}
有没有人知道如何通过在数组上正确绑定 v-model 来实现这一点?
一个示例 fiddle,我正在尝试这样做但未能成功。
我认为你的问题与 Vuetify 无关。
与此类似,使用带有普通 HTML 输入的 BootstrapVue 或 Vue 时,您会遇到同样的问题。事实上,它与 Vue 几乎没有任何关系,因为在输入元素上使用两种方式绑定的任何其他库中都会遇到同样的问题。
首先,:value
和 v-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 来源)。显然,您可以 tweak/improve 它根据类型提供默认值。