Я пишу небольшую оболочку для компонента <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>

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

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

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

1
lukas_o 13 Сен 2018 в 16:12

2 ответа

Лучший ответ

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

Также вы можете установить для параметра inheritAttrs значение false и привязать {{ X1}} вручную, поскольку вы заключили элемент ввода в 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 к числу (это строка), но оставлю это на ваше усмотрение.

1
Decade Moon 13 Сен 2018 в 13:38

У вас есть пара вещей, которые здесь идут не так, но самое главное - вы смешиваете 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

0
peter.edwards 13 Сен 2018 в 14:23