目次
全体概要
親 → Login.vue
子 → FormButton.vue、FormInput.vue、FormSelect.vue
今回は、上記の4つのvueテンプレートを用いて説明します。
親→子へデータを渡す:<propsで受け取る>
親コンポーネントでは、コンポーネント内に属性をキーとしてデータを持たせるだけです。
ここでは、button_nameをキーとしているので、子コンポーネントではbutton_nameで展開できます。
Login.vue
<template>
<FormButton button_name="ログインする" />
</template>
<script>
import FormButton from "~/components/FormButton.vue"
export default {
components:{
FormButton
}
}
</script>
FormButton.vue
そして子のコンポーネントでは、propsを用いてデータを受け取ります。
Login.vueで定義したbutton_nameをpropsで指定しないと、取得できません。
<template>
<button type="submit">{{ button_name }}</button>
</template>
<script>
export default {
props: [ "button_name" ]
}
</script>
子→親の関数を実行:<$emitでイベントを発行>
やりたいことは、
FormButton.vueで定義したbutton要素をクリックしたら、Login.vueで定義しているlogin()を実行させることです。
流れは、
FormButton.vue内のbuttonをクリック
↓
FormButton.vue内で定義したissueEvent()を実行
↓
issueEvent内の$emitで親で発火させるイベント名(第1引数)と渡す値(第2引数)を指定
です。
FormButton.vue
<template>
<!-- @clickを追加 -->
<button @click="issueEvent" type="submit">{{ button_name }}</button>
</template>
<script>
export default {
props: [ button_name ],
// 追加
methods:{
issueEvent(){
this.$emit("signalEvent")
}
}
}
</script>
Login.vue
FormButton.vueの$emitで指定されたsignalEventを実行して、指定した処理login()を実行します。
<template>
<!-- 親側で子のイベントを検知して、親で定義した関数を実行 -->
<FormButton button_name="ログインする" @signalEvent="login" />
</template>
<script>
import FormButton from "~/components/FormButton.vue"
export default {
components:{
FormButton
},
// 追加
methods:{
login(){
// ログイン処理
}
}
}
</script>
@signalEvent=”login”は、
子側で、「signalEventが発火したら、親側のlogin()を実行してね」、っていう合図です。
今回は、子のbutton要素をクリックした情報を親に渡すだけなので、$emitの第2引数には、何も定義していません。
子→親にデータを渡す:<$emitの第2引数>
ここでは、書き方を2種類紹介します。
ここからは、FormInput.vueを使って説明していきます。
パターン1
FormInput.vue
<template>
<div class="form-input">
<label>{{ label }}:</label>
<input v-model="value" @input="issueEvent" type="text" />
</div>
</template>
<script>
export default {
props: ["label", "value"],
methods: {
issueEvent(e){
// 第2引数で親に渡したいデータを指定
this.$emit("signalEvent",e.target.value)
}
}
}
</script>
Login.vue
<div class="form-container">
<FormInput label="メールアドレス" :value="email" @signalEvent="getEmail"></FormInput>
<FormInput label="パスワード" :value="password" @signalEvent="getPass"></FormInput>
<FormButton button_name="ログインする" @signalEvent="login"></FormButton>
</div>
<script>
import FormInput from "~/components/Input.vue"
import FormButton from "~/components/Button.vue"
export default {
components: {
FormInput,
FormButton
},
data() {
return {
email: null,
password: null,
}
},
methods: {
// 引数のvalueは、子コンポーネントの$emitの第2引数で指定した値を取得
getEmail(value){
this.email = value
},
getPass(value){
this.password = value
},
login() {
// ログイン処理
}
}
}
</script>
valueには、子コンポーネントのthis.$emitで指定した第2引数の値が入ります。
パターン2(推奨:v-modelを使用)
こちらのパターンでは、v-modelを使用するやり方です。v-modelについての理解が必要なので、まずは説明をします。
<template>
<input v-model="email">
</template>
上↑と下↓は、同義です。
<template>
<input
v-bind:value="email"
v-on:input="email = $event.target.value">
</template>
省略形で書くならば、
<template>
<input
:value="email"
@input="email = $event.target.value">
</template>
つまりv-modeの1行は、
・inputイベントによるvalueの変化の取得
・data内のemailのバインド
の両方をしているということです。
FormInput.vue
<template>
<div class="form-input">
<label>{{ label }}:</label>
<input :value="value" @input="issueEvent" type="text" />
</div>
</template>
<script>
export default {
props: ["label", "value"],
methods: {
issueEvent(e){
// 親側ではv-modelを使用しておりデフォルトは@inputなので"input"を指定
this.$emit("input", e.target.value)
}
}
}
</script>
Login.vue
v-modelは、@inputを内包しているので、パターン1で記述した@signalEvent=”〜”を書かなくても良いというメリットがあります。
<div class="form-container">
<FormInput label="メールアドレス" v-model="email"></FormInput>
<FormInput label="パスワード" v-model="password"></FormInput>
<FormButton button_name="ログインする" @signalEvent="login"></FormButton>
</div>
<script>
import FormInput from "~/components/Input.vue"
import FormButton from "~/components/Button.vue"
export default {
components: {
FormInput,
FormButton
},
data() {
return {
email: null,
password: null,
}
},
methods: {
login() {
// ログイン処理
}
}
}
</script>
セレクトボックス
Login.vue
<div class="form-container">
<FormInput label="メールアドレス" v-model="user_name" />
<span>@</span>
<FormSelect :options="[
{name: 'gmail.com', value: '@gmail.com'},
{name: 'yahoo.co.jp', value: '@yahoo.co.jp'}
]" v-model="domain" />
<FormInput label="パスワード" v-model="password" />
<FormButton @signalEvent="login" button_name="ログインする" />
</div>
<script>
import FormInput from "~/components/Input.vue"
import FormSelect from "~/components/Select.vue"
import FormButton from "~/components/Button.vue"
export default {
components: {
FormInput,
FormSelect,
FormButton
},
data() {
return {
user_name: null,
domain: null,
password: null,
}
},
methods: {
login() {
// ログイン処理
}
}
}
</script>
Form.Select.vue
<template>
<select @change="issueEvent" >
<option v-for="option in options"
:key="option.name"
:value="option.value"
:selected="option.name == 'gmail.com'"
>{{ option.name }}</option>
</select>
</template>
<script>
export default {
props: {
// 中身は統一:[{name: "表示名", value: "値"}]
options: {
type: Array,
required: true
}
},
methods: {
issueEvent(e){
this.$emit("input", e.target.value)
}
}
}
</script>
今回は、以上です。
他にも良い書き方などあればコメント欄からコメントください!