v-модель и дочерние компоненты?

У меня есть форма и привязка ввода с использованием v-модели:

<input type="text" name="name" v-model="form.name">

Теперь я хочу извлечь вход и сделать его собственным компонентом, как вы привязываете значения дочернего компонента к объекту form.name?

Ответы

Ответ 1

Как указано в документации,

v-model - это просто синтаксический сахар для:

<input
  v-bind:value="something"
  v-on:input="something = $event.target.value">

Чтобы реализовать директиву v-model для настраиваемого компонента:

  • указать value для компонента
  • установите свойство данных в значение value prop в методе data (так как вы не должны изменять значение prop изнутри компонента).
  • испускать input событие со значением свойства данных всякий раз, когда он изменяется

Вот простой пример:

Vue.component('my-input', {
  template: '
    <div>
      My Input:
      <input v-model="inputVal">
    </div>
  ',
  props: ['value'],
  data() {
    return { inputVal: this.value }
  },
  watch: {
    inputVal(val) {
      this.$emit('input', val);
    }
  }
})

new Vue({
  el: '#app',
  data() {
    return { foo: 'a', bar: 'b' }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
  <!-- using v-model... -->
  <my-input v-model="foo"></my-input>
  
  <!-- is the same as this... -->  
  <my-input :value="bar" @input="bar = $event"></my-input>

  {{ foo }}<br>
  {{ bar }}
</div>

Ответ 2

используйте sync в своем основном экземпляре, и если вы используете vue> 2.2, вам нужно использовать emit в компоненте.

Проверьте этот документ: https://alligator.io/vuejs/upgrading-vue-2.3/#propsync

Простой пример (с vue 2.5):

Vue.component('my-input', {
	template: '<input v-on:keyup="onChange($event)" :value="field"></div>',
	props: ["field"],
	methods: {
		onChange: function (event) {
			this.$emit('update:field', event.target.value);
		}
	}
});

var vm = new Vue({
	el: '#app',
	data:{val: ''},
});
h1 span { color: red }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>

<div id='app'>
 <h1>
   value
   <span>{{ val }}</span>
 </h1>
	<my-input :field.sync="val">
   </my-input>
 </div>

Ответ 3

Вы также можете указать события :value и @input для дочернего компонента и использовать события вместо создания часов.

MyInput.vue

<template>
  <input 
    :value="value" 
    @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  props: ['value']
};
</script>

Screen.vue

<template>
  <my-input v-model="name" />
</template>

<script>
import MyInput from './MyInput.vue';

export default {
  components: { MyInput },
  data() {
    return {
      name: ''
    }
  }
};
</script>

Ответ 4

В приведенном ниже примере показано, как установить модель из родительского в дочерний компонент и синхронизировать данные между ними. Это очень полезно, когда вы разделяете формы приложения на разные компоненты и используете их в разных контекстах. Таким образом, вы можете использовать, например, фрагменты (компоненты) формы в разных местах, не повторяя себя.

РОДИТЕЛЬСКИЙ КОМПОНЕНТ

<template lang="pug">

  .parent
    Child(:model="model")
    br


    label(for="c") Set "c" from parent  
    input(id="c", v-model="model.c")

    .result.
      <br>
      <span> View from parent :</span>
      <br>
      a = {{ model.a }} 
      <br>
      b = {{ model.b }}
      <br>
      c = {{ model.c }}


</template>

<script>

import Child from './components/child.vue'

export default {

name: "App",

components: {
  Child
  },

  data() {
    return {
      // This model is set as a property for the child
      model: {
        a: 0,
        b: 0,
        c: 0
      }
    }
  },




};
</script>

ДЕТСКИЙ КОМПОНЕНТ

<template lang="pug">

  .child
    label(for="a") Set "a" from child  
    input(id="a", v-model="internalModel.a", @input="emitModel")
    br
    br

    label(for="b") Set "b" from child  
    input(id="b", v-model="internalModel.b", @input="emitModel")

    .result
      br
      span View from child
      br
      | a = {{ internalModel.a }} 
      br
      | b = {{ internalModel.b }}
      br
      | c = {{ internalModel.c }}

</template>

<script>


export default {

  name: 'Child',
  props: {
    model: {
      type: Object
    }
  },

  data() {
    return {
      internalModel: {
        a:0,
        b:0,
        c:0
      }
    }
  },

  methods: {
    emitModel() {
      this.$emit('input', this.internalModel)
    }
  },
  mounted() {
    this.internalModel = this.model;
  }

}
</script>