Vue двусторонняя привязка в «прозрачном» упакованном компоненте ввода - PullRequest
0 голосов
/ 13 сентября 2018

Я пишу небольшую оболочку для компонента <input>. Я следил за документацией, и это учебник .

Однако у меня возникли проблемы с двусторонней привязкой. Я ожидаю, что мой компонент будет работать с v-model. Привязка, кажется, работает нормально для обновления значения, но когда я изменяю само значение, компонент не обновляется. Я также прочитал о прозрачных оболочках , что, похоже, моя проблема здесь.

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

<template id="numInput" :v-on="listeners">
  <div>
    <!-- note the div here, it works without, but that's not what I want -->
    <input ref:inp type="number" :value="num" @input="updateSelf($event.target.value)" @blur="reset" :class="{rc: isNegative}" />
  </div>
</template>

Вы можете найти весь пример кода здесь .

Привязка работает в одну сторону (изменение ввода текста). Но компонент ввода не обновляется другим способом (например, нажатие кнопки)

Любая помощь приветствуется!

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

Пользовательские компоненты ввода должны быть без сохранения состояния (если у вас нет причин не делать этого); это означает, что значение компонента должно предоставляться реквизитом, а не локальным состоянием (данными). У вашего <num-input> компонента отсутствует value опора, необходимая для работы v-model.

Также может потребоваться установить для параметра inheritAttrs значение false и связать $attrs вручную, поскольку вы обернули входной элемент в div.

Вот небольшой пример того, как это должно быть:

Vue.component('num-input', {
  template: '#numInput',
  inheritAttrs: false,
  props: ['value'],
  computed: {
    isNegative() {
      return this.value < 0;
    },
  },
  methods: {
    onInput(e) {
      // You can conditionally do this after validation
      this.$emit('input', e.target.value);
    },
    onBlur() {
      if (this.isNegative) {
        this.$emit('input', 0);
      }
    },
  },
});

new Vue({
  el: '#app',
  data: {
    num: 0,
  },
});
.negative { color: red; }
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>

<div id="app">
  <num-input v-model="num"></num-input>
  <button @click="num++">+1</button>
  <p>{{ num }}</p>
</div>

<template id="numInput">
  <div>
    <input type="number" :value="value" @input="onInput" @blur="onBlur" :class="{ negative: isNegative }" v-bind="$attrs">
  </div>
</template>

Я не привел значение, генерируемое событием input, к числу (это строка), но я оставлю это на ваше усмотрение.

0 голосов
/ 13 сентября 2018

У вас есть пара вещей, которые идут не так, но наиболее фундаментальным является то, что вы смешиваете Nom и NUM в своем коде.Я немного переработал ваш компонент и превратил ваши данные num в свойство, а затем привязал его к вашему основному приложению.

Вот ваш переработанный код ...

Vue.config.devtools = true;

// global component registration
Vue.component('num-input', {
  template: '#numInput', 
  props: ['value'],
  computed: {
    isNegative: function() {
      console.log('num: ' + this.value)
      return this.value < 0;
    },
    listeners: function () {
      return this.$listeners;
    },
  },
  methods: {  
    reset () {
      if (this.isNegative) {
        this.$emit('input', 0)        
      }
    }
  },
});

 new Vue({
   el: '#container',
   data: {
     num: 0,
   },
   methods: {
     increaseBy1() {
       this.num++;
       console.log("increased by 1");
     },
   },
 });

Чтобы просмотретькод и html-привязку. Я разветвил ваш код, и его можно найти по адресу ...

https://codepen.io/peterpde/pen/BOVQzg

...