vue3 を触っていて、2つのつまずきがあったので解決方をまとめました。
■つまずき1:v-modelが動かない
<template>
<input
@input="$emit('input', $event.target.value)"
@change="$emit('change', $event.target.value)"
/>
</template>
<script>
export default {
name: "AInput",
};
</script>
このコンポーネントにv-modelでバインドする際にvue3だとうまく動かないようでした。
<template>
<div class="container">
コードを入力してください。
<AInput
v-model="code"
@change="onChange"
type="tel"
/>
<p>コード: {{ code }}</p>
</div>
</template>
<script>
import AInput from "./components/AInput.vue";
export default {
name: "App",
components: {
AInput,
},
data() {
return {
code: '',
};
},
methods: {
onChange(v) {
console.log('changed')
console.log(v)
}
}
};
</script>
■原因 v-modelの仕様が変わった
vue3 の v-modelの仕様が、v2から変わっていました。
https://v3.ja.vuejs.org/guide/migration/v-model.html
破壊的変更: カスタムコンポーネントで使用する場合に、v-model のプロパティとイベントのデフォルト名が変更されます。
プロパティ: value -> modelValue
イベント: input -> update:modelValue
破壊的変更: v-bind の .sync 修飾子とコンポーネントの model オプションは削除され、v-model の引数に置き換えられます。
新規: 同じコンポーネントに複数の v-model バインディングが可能になりました。
新規: カスタムの v-model 修飾子を作成する機能が追加されました。
こちらの記事に詳しく記載を頂いていました。
■解決法 $emit するイベントを update:modelValue に変更
記載の通り、AInput.vue の @input の $emit するイベントを update:modelValue に変更するとv-modelが動きました。
<template>
<input
@input="$emit('update:modelValue', $event.target.value)"
@change="$emit('change', $event.target.value)"
/>
</template>
<script>
export default {
name: "AInput",
};
</script>
■つまずき2:changeイベントが2回発火される
また同時に、changeが2回$emitされる現象が起こりました。
■原因 vue3から $emit の仕様が変わった
下記のページとRFCを見ると、コーディングの意図を明示的にするために、$emitするイベントをwhite list化することを求める変更が行われたようでした。
■解決法 $emit するイベントをemitsに記述
こちらのissueの回答の通り、AInput.vue の $emit するイベントを 事前に把握して
export default {
emits: ["update:modelValue","change"],
}
と記述することでchangeが2回発火されなくなりました。
<template>
<input
@input="$emit('update:modelValue', $event.target.value)"
@change="$emit('change', $event.target.value)"
/>
</template>
<script>
export default {
name: "AInput",
emits: ["update:modelValue", "change"],
};
</script>
以上2つのつまずきについて解決方法をまとめました。
2つ目の方は、2回イベントが$emitされるのは結構危ないので気を付けたいと思いました。
以上です。