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>