はじめに
インプット要素を使いまわしたいなあと思っていたところ、ひらめいたので実装したらうまくったので紹介します。
目的
v-model='hugeObject'
ができるカスタムコンポーネントを作る
方法
Reduxの考え方に影響を受けています。
インプットエレメントをラップした「インプットコンポーネント」を作る
以下のように、インプットエレメントをラップします。
FormText.vue
<template>
<label class="FormText" :for="name">
<span>{{ label }}</span>
<input type="text" :id="id" :name="name" v-model="text">
</label>
</template>
<script>
export default {
name: 'FoundationFormText',
props: {
id: String, // input要素のid
label: String, // フォームのラベルに表示するテキスト
name: String, // input要素のname
value: String, // input要素のvalue
},
computed: {
text: {
get() { return this.value },
set(text) { this.$emit('input', text) },
},
},
}
</script>
このようにすることで、インプットエレメントをラップしたインプットコンポーネントを作成することができます。
「インプットコンポーネント」を複数所有するコンポーネントを作る
次に、上記で作成したコンポーネントたちを組み合わせたコンポーネントを作成します。
次い、 lastName
と firstName
を処理するコンポーネントを作ります。
CustomerForm.vue
<template>
<div>
<FormText v-model="lastName" id="last" name="last" label="姓" />
<FormText v-model="firstName" id="first" name="first" label="名" />
</div>
</template>
<script>
import FormText from './FormText.vue'
export default {
name: 'CustomerForm',
components: { FormText },
props: {
value: {
type: Object,
validator: customer => {
if (typeof customer.lastName !== 'string') return false
if (typeof customer.firstName !== 'string') return false
return true
},
},
},
computed: {
lastName: {
get() { return this.value.lastName },
set(lastName) { this.$emit('input', { ...this.value, ...{ lastName }}),
},
firstName: {
get() { return this.value.firstName },
set(firstName) { this.$emit('input', { ...this.value, ...{ firstName }}),
},
},
}
子コンポーネントに渡したいデータごとにcomputed propertyを作成します。
また、上記の例では 親コンポーネントから value
propへ渡される値(Customer型)は、 lastName
と firstName
以外のデータを受け取っても問題ないです。
このように定義したコンポーネントを使います。
RegisterForm.vue
<template>
<div>
<CustomerForm v-model="customer" />
<OtherForm v-model="customer.otherObject" />
</div>
</template>
<script>
import CustomerForm from './CustomerForm.vue'
import OtherForm from './OtherForm.vue'
export default {
name: 'RegisterForm',
components: { CustomerForm, OtherForm },
data() {
return {
customer: {
lastName: '',
firstName: '',
otherObject: {},
},
},
},
}
</script>
まとめ
v-model
にコミュニケーションをまとめることで、再利用性の高いコンポーネントを作成できたと言えます。