88419


以下の内容についてお聞きしたいです。

## 概要

以下の2つのコンポーネントを作成しました。

  * App.vue

[code]

    <template>
      <h1>My Counter</h1>
      <div>count: {{ count }}</div>
      <NumberInput v-model.numberOnly="interval" />
      <p>interval: {{ interval }}</p>
      <button @click="insertCount">insert</button>
    </template>
    
    <script>
    import NumberInput from './components/NumberInput.vue';
    
    export default {
      components: {
        NumberInput,
      },
      data() {
        return {
          count: 0,
          interval: 0
        }
      },
      methods: {
        insertCount() {
          this.count += this.interval;
        }
      },
      watch:{
        interval(value) {
          if (value >= 9999) {
            this.interval = 9999;
          }
    
          if (value <= 0) {
            this.interval = 0;
          }
        }
      }
    };
    </script>
    
[/code]

  * NumberInput.vue

[code]

    <template>
      <input :value="modelValue" @input="emitValue" type="number" />
    </template>
    
    <script>
    export default {
      name: 'NumberInput',
      emits: ['update:modelValue'],
      props: {
        modelValue: {
          type: Number,
          default: 0,
        },
        modelModifiers: {
          default: () => ({})
        }
      },
      methods: {
        emitValue({ target: { value } }) {
          if (this.modelModifiers.numberOnly && value === '') {
            value = 0;
          }
    
          this.$emit('update:modelValue', Number(value));
        }
      }
    }
    </script>
    
[/code]

NumberInputのコンポーネントに入力した値は9999を越したら、watchで強制的に9999になります。  
なのでフォームに9999より大きい値を入力しても、9999より大きくならないと思っていました。  
ただ、以下のように9999111という値が入力できてしました。  
[![fail](https://i.stack.imgur.com/feT5L.gif)](https://i.stack.imgur.com/feT5L.gif)

NumberInputを使わずに以下のようにinputを使ったら

[code]

    <input v-model="interval" type="number" />
    
[/code]

フォームの中身も`9999111`と入力しようとしても、9999より大きくはなりませんでした。

## 実現したい動作

内部的にintervalは9999止まりになっているようですが、form内では9999を越しているのが腑に落ちていない状態です。inputを使った時のように、form内の値も9999以上にはキーボード入力してもならないようにしたいです。

## お聞きしたいこと

  1. この挙動になる原因と実現したい動作に向けて修正方法をお聞きしたいです

プロジェクトは以下のリンクにarchive.zipで置いてあるので

[code]

    yarn install
    yarn run dev
    
[/code]

で動作するかと思います。  
リンク: <https://beam.cafe/d/KecBT9aB>  
よろしくお願いいたします。


CC BY-SA 4.0
2021-09-18T08:48:10.077
82563
2022-04-20T12:19:22.430
2021-09-19T01:02:58.533
2238
24870
question
javascript vue.js
カスタムコンポーネントにv-modelを使用した際に、親でwatchしている変数が更新されない


# 原因

`v-model` が通常動作しているのは、 `update:modelValue` によって、親側で `v-model` で貼り付けた data の
interval フィールドが更新され、そして更新されたことを検知した Vue Reactivity
のシステムが、それに依存しているコンポーネント(今回で言えば `NumberInput`)を再 render & update
することによって、親の反映を実際の dom に反映する、ということが行われるからっぽいです。

今回、この問題の挙動がおきるのは 9999 からさらに文字を入力した時で、その場合には、親側は watch によって、結局 9999
から変更が起きなかったことにより、 this.interval の変更が発生せず、 NumberInput の再 render の結果も変わらず、なので
update が発動しない、ということが起きている様子です。

[code]

        emitValue({ target: { value } }) {
          if (this.modelModifiers.numberOnly && value === '') {
            value = 0;
          }
    
          this.$emit('update:modelValue', Number(value));
          this.$forceUpdate()
        }
    
[/code]

なので、上記のように、 update を強制すれば、おそらく意図通りの挙動になることを手元で確認しました。


CC BY-SA 4.0
2022-04-20T12:19:22.430
88419
2022-04-20T12:19:22.430
754
82563
answer