Vuejs - 在运行时解析深层嵌套的 v-model 属性
Vuejs - Resolve deep nested v-model property at runtime
我有一个动态表单,其中输入控件的 v 模型在运行时解析。它适用于简单的 0 或 1 级深度对象。但我不知道如何让它适用于超过 1 级深度的嵌套属性。
我的 HTML 是这样的:
<div v-for="element in elements" v-bind:key="element.name">
<q-input v-model="inputdata[element.model]"></q-input>
</div>
Javascript
<script>
export default {
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
}
},
}
</script>
包含数据的数组:
elements: [
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street', // does not work. i want to be able to set any level deep property
name: 'street'
}
]
只要我尝试将 属性 设置为 0 或第 1 级(输入数据或 inputdata.account),它就可以工作。
如何让像 inputdata.account.name 或 inputdata.account.address.street 这样深的 属性 工作?
也许您可以使用自定义迭代方法代替 v-model
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
new Vue({
el: '#app',
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
elements: [
{
type: 'text',
hint: 'Name',
label: 'Name',
model: 'account.name',
name: 'name'
},
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street',
name: 'street'
},
]
}
},
methods: {
getInputValue(model){
return getValueByModel(model, this.inputdata);
},
updateInputValue(model, event){
let newValue = event.target.value;
this.inputdata = {...setValueByModel(model, this.inputdata, newValue)};
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="app">
<div v-for="element in elements" v-bind:key="element.name">
<input :value="getInputValue(element.model)"
@input="updateInputValue(element.model, $event)"
:placeholder="element.name"/>
</div>
{{ inputdata }}
</main>
我有一个动态表单,其中输入控件的 v 模型在运行时解析。它适用于简单的 0 或 1 级深度对象。但我不知道如何让它适用于超过 1 级深度的嵌套属性。
我的 HTML 是这样的:
<div v-for="element in elements" v-bind:key="element.name">
<q-input v-model="inputdata[element.model]"></q-input>
</div>
Javascript
<script>
export default {
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
}
},
}
</script>
包含数据的数组:
elements: [
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street', // does not work. i want to be able to set any level deep property
name: 'street'
}
]
只要我尝试将 属性 设置为 0 或第 1 级(输入数据或 inputdata.account),它就可以工作。
如何让像 inputdata.account.name 或 inputdata.account.address.street 这样深的 属性 工作?
也许您可以使用自定义迭代方法代替 v-model
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
new Vue({
el: '#app',
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
elements: [
{
type: 'text',
hint: 'Name',
label: 'Name',
model: 'account.name',
name: 'name'
},
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street',
name: 'street'
},
]
}
},
methods: {
getInputValue(model){
return getValueByModel(model, this.inputdata);
},
updateInputValue(model, event){
let newValue = event.target.value;
this.inputdata = {...setValueByModel(model, this.inputdata, newValue)};
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="app">
<div v-for="element in elements" v-bind:key="element.name">
<input :value="getInputValue(element.model)"
@input="updateInputValue(element.model, $event)"
:placeholder="element.name"/>
</div>
{{ inputdata }}
</main>