In VueJS is it possible to bind something with v-model that is then rebound to another child?

廉价感情. 提交于 2019-12-02 10:27:24

问题


I have an app for which I'm creating a custom component that will output a single row of a table. It contains a numeric field which is user-adjustable, and so within that custom component I'm using another custom component from the quasar framework (q-numeric). I'm struggling to see how I can bind a variable at the top-level through 2 components - perhaps it can't be done directly, but I was hoping to avoid lots of extra code in the middle component. So far it looks like this from the top down:

In the App.vue template, I have lines like this:

<config-item v-model="numParticipants">Number of Participants</config-item>

ConfigItem.vue, looks like this:

<template>
  <tr>
    <td class="text-right"><slot></slot></td>
    <td class="text-right">
      <q-numeric
        v-model="value"
        :min="min"
        :max="max"
        :step="step"
        @input="$emit('input', value)"
      ></q-numeric>
    </td>
  </tr>
</template>

<script>
  export default {
    props: {
      label: String,
      value: Number,
      min: {
        type: Number,
        default: 1
      },
      max: {
        type: Number,
        default: 1000
      },
      step: {
        type: Number,
        default: 1
      }
    }
  }
</script>

But of course that won't work, because I'm now binding the property value to the q-numeric, which will mutate it. Really, I wan't to bind the top-level variable numParticipants to the q-numeric - is it possible to implement some kind of 'pass through' within my config-item component? Or does my component need to have it's own data element which it initialises from the passed-in properties, and updates in response to the q-numeric? I know I can do that, but I was hoping for a cleaner solution...


回答1:


Update: You can propagate v-model-ability down a hierarchy by making a writable computed based on the prop (the prop must be named 'value'). The get function obviously returns the prop value; the set function does the $emit.

The computed spec is entirely fixed, so I have extracted it as a constant.

const vModelComputed = {
  get() {
    return this.value;
  },
  set(newValue) {
    this.$emit('input', newValue);
  }
};

new Vue({
  el: '#app',
  data: {
    numParticipants: 1
  },
  components: {
    middleComponent: {
      props: ['value'],
      template: '<div>Value: {{value}} <q-numeric v-model="localValue"></q-numeric></div>',
      computed: {
        localValue: vModelComputed
      },
      components: {
        qNumeric: {
          props: ['value'],
          template: '<div><input v-model="localValue" type="number"> inner value: {{value}}</div>',
          computed: {
            localValue: vModelComputed
          }
        }
      }
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<div id="app">
  Participants: {{numParticipants}}
  <middle-component v-model="numParticipants"></middle-component>
</div>



回答2:


This is what I ended up with - seemed like the simplest approach. I was kind of hoping Vue would have a mechanism to hide this away when the 'middle' component effectively promises not to change the model, but just wants to hand it on to a child.

Basically, I created an intermediary data element ivalue, and initialised it in the mounted() event, and use the input() event of the child to emit an input() event back to the parent.

<template>
  <tr>
    <td class="text-right"><slot></slot></td>
    <td class="text-right">
      <q-numeric
        v-model="ivalue"
        :min="min"
        :max="max"
        :step="step"
        @input="$emit('input', ivalue)"
      ></q-numeric>
    </td>
  </tr>
</template>

<script>
  export default {
    data: () => ({
      ivalue: 0
    }),
    mounted () {
      this.ivalue = this.value
    },
    props: {
      label: String,
      value: Number,
      min: {
        type: Number,
        default: 1
      },
      max: {
        type: Number,
        default: 250000
      },
      step: {
        type: Number,
        default: 1
      }
    }
  }
</script>


来源:https://stackoverflow.com/questions/43606355/in-vuejs-is-it-possible-to-bind-something-with-v-model-that-is-then-rebound-to-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!