自作したコンポーネントにもv-modelを実装できる。
その実装方法を説明する。
文字入力UIのデザインを統一する想定で、UiTextInputというコンポーネントを作成する。
文字入力UIのデザインを統一するために実装する機会は多そう。そうでもない?Vuetifyを使う?
結論はこちら
UiTextInputの実装
v-modelを実装するには、
- propsプロパティにvalueを設定して、親コンポーネントから値を受け取る。
- inputイベントを$emit(通知)して、親コンポーネントに変更後の値を渡す。
必要がある。
そのため、computedにgetter/setterを作成し、inputのv-modelとの値の受け渡しを行うようにした。
- getterでpropsのvalueを返却して、親コンポーネントから値を受け取る。
- setterでinputイベントを$emitして、親コンポーネントに変更後の値を受け渡す。
実装したソースコードが以下である。
<template>
<input v-model="text" placeholder="入力してください">
</template>
<script>
export default {
props: {
value: {
type: String
}
},
computed: {
text: {
get() {
return this.value;
},
set(text) {
this.$emit("input", text);
}
}
}
}
</script>
<style scoped>
input {
display: block;
border-width:0px;
border-style:None;
font-size: 18px;
background-color: rgba(0,0,0,0);
outline: 0;
border-bottom: 1px solid #d0d0d0;
}
</style>
使い方
通常のinputのv-modelと同様に使用できる。
UiTextInputコンポーネントを呼び出して、v-modelに値を指定する。
<template>
<div>
<h2>v-modelのサンプル</h2>
<div class="field">
<label>名前 </label>
<UiTextInput v-model="text" class="input" />
</div>
<p v-if="text">こんにちは、 {{text}} さん!</p>
</div>
</template>
<script>
import UiTextInput from "./UiTextInput.vue";
export default {
components: {
UiTextInput
},
data() {
return {
text: ""
};
}
}
</script>
<style scoped>
.field {
display: flex;
}
label {
flex-basis: 100px;
}
.input {
flex-grow: 1;
}
</style>
データフロー
文章とソースコードによる説明だとイメージしづらいかもしれないので、補足としてデータフローで図解する。
使用する側(親コンポーネント)からUiTextInput(子コンポーネント)へ値を渡す
UiTextInput(子コンポーネント)から使用する側(親コンポーネント)へ値を渡す
結論
コンポーネントでv-modelを実装する際は、
- propsのvalueで、親コンポーネントから値を受け取る。
- inputイベントを$emit(通知)して、親コンポーネントに値を渡す。
をすれば良い。