vueコンポーネントを作成する。
〜contents〜
- PropとEmit
- v-bindとv-on
コンポーネントとは?
Vueでは、各機能の最小単位の部品をコンポーネントとして創り、必要な各箇所でその部品を組み合わせてページを作っていく。
今回のFormの例では、子コンポーネントはテキスト入力の部品コンポーネントやボタンの部品コンポーネントが相当し、これらを束ねるFormコンポーネントが親コンポーネントという関係になる。
vueファイルのざっくりした理解。
<template>
<!--HTMLを書く空間-->
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'; //おまじない
@Component //おまじない
export default class コンポーネント名 extends Vue {
/////////////コンポーネント内で使用する変数、関数の定義//////////////
}
</script>
<style scoped lang="scss">
/////////////スタイルを書くところ//////////////
</style>
vue-property-decorator
は、TypeScriptで書く用のツールらしい。
各コンポーネントは自身の変数の値や関数コールを知ることはできるが、このままでは外部の値を知ることはできない。
つまり、テキスト入力のコンポーネントに何を入力されても、親のFormコンポーネントからは知れないし、ボタンのコンポーネントは入力値に基づいた活性非活性を分岐することはできない。
そこで、各コンポーネント間で値の授受や、関数コールを行う仕組みを利用する。それがProp
とEmit
である。
重要なことはこれらは一方向の関係であること。
Prop
は親コンポーネントから子コンポーネントへ値を渡す時に使用し、Emit
はこコンポーネントから親コンポーネントの関数をコールする時に使用する。(逆に、子は親の変数を直接変えないし、親が子の関数は動かさない。)
まとめ
Prop:親→子へのデータ受け渡し
Emit:子→親へのデータ受け渡し
つくってみる
ここでは、TextBoxに入力があったらボタンを活性にするFormを作る。
流れは、TextBoxコンポーネントで入力されたことをトリガにFormコンポーネントへEmitして値が入力されたことを通知する。次に、FormコンポーネントではPropを用いてButtonコンポーネントの活性を変更する。
まずは、Prop
とv-bind
の扱い方。
Form(親)からButton(子)へ活性非活性を指定する。
<template>
<div>
<Button v-bind:disabled="disabled"/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Button from '@/components/Button.vue'
@Component({
components:{
Button
}
})
export default class Form extends Vue {
private disabled: boolean = false
}
</script>
<template>
<div>
<button class="button" :class="{disabled: disabled}">決定</button>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
export default class Button extends Vue {
@Prop()
private disabled: boolean
}
</script>
<style scoped lang="scss">
.button{
text-align : center;
background-color : #f0b434; //活性の色
cursor : pointer;
border : solid 1px;
float : center;
}
.disabled{
background-color : #7d837d; //非活性の色
}
</style>
子コンポーネントでの@Prop
は親コンポーネントから受け取るデータとして宣言している。
これにより変数disable
は親コンポーネントから代入できる。
@Prop()
private disabled: boolean //子コンポーネントの変数。
では親からはどのように代入するか?
まずは、Buttonコンポーネントが使えるようにならないといけないのでインポートする。
//インポート
import Button from '@/components/Button.vue'
//コンポーネントの定義
@Component({
components:{
Button
}
})
export default class Form extends Vue {
private disabled: boolean = false //親コンポーンネントの変数。
}
親コンポーネントからButtonコンポーネントのdisable
に値を渡してあげる。この時、渡す対象の子コンポーネントの値にはv-bind:
を付して、呼び出す際に値を指定する。
<Button v-bind:disabled="disabled"/>
上記のケースでは、ボタンが使用可能かを示すdisabled
はv-bind:
が付され、代入される「disable」は定数ではなく、親コンポーネントのdisabled
という変数である。なお、v-bind:
は省略して:
と表記することもできる。
親から指定されるとdisable
により子コンポーネントのclass
にdisabled: false
指定され、disable
スタイルが外れる。
<button class="button" :class="{disabled: disabled}">決定</button>
なお、<button class="button" :class="{disabled}">決定</button>
としても同じ。
まとめ
変数を渡す方法
<コンポーネント名 v-bind:子コンポーネントの変数="親コンポーネントの変数" />
変数を受け取る方法
@Prop()
//子コンポーネントの変数定義
次にEmit
とv-on
について
Button(子)からForm(親)へクリックされたことを通知する。
<template>
<div>
<Button v-bind:disabled="disabled" v-on:Clicked="click"/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Button from '@/components/Button.vue'
@Component({
components:{
Button
}
})
export default class Form extends Vue {
private disabled: boolean = false
private click(): void{
console.log("I'm parent")
}
}
</script>
<template>
<div>
<button class="button" :class="{disabled: disabled}" v-on:click="Clicked">決定</button>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Emit } from 'vue-property-decorator';
@Component
export default class Button extends Vue {
@Prop()
private disabled: boolean
//Emitの引数のイベント名はメソッド名と同じ場合は省略可能。この場合省可能
@Emit('Clicked')
private Clicked():void {
console.log("I'm child")
}
}
</script>
@Emit
は子コンポーネントから親コンポーネントへ連絡する際に用いる。書式は以下。
@Emit('親側で関数を指定する時のイベント名')
private 子の中で呼ぶ時のメソッド名(): 戻り値{
//処理
}
トリガされる方では以下。
v-on:イベント名="呼び出す親自身の関数"
上記の例では、子コンポーネントのv-on:click="Clicked"
によりクリックイベントが発生した際に子コンポーネント自身の関数Clicked
が呼び出される。さらに、この関数Clicked
はEmitが指定されており、この関数Clicked
が呼ばれると、引数に指定した親コンポーネントのClicked
イベントを発生させる。
親コンポーネント側ではv-on:Clicked="click"
によりClicked
イベント発生をトリガにして親自身の関数click
が呼ばれる。
このようにして、このボタンコンポーネントをクリックすると以下のようにコンソールに出力される。
I'm child
I'm parent
なお、上の例のようにイベント名=メソッド名の場合にはEmitの引数を省略することができる。
また、大文字小文字は区別されず、キャメルケースとケバブケースは勝手に変換され、バインドできる。
v-bind
同様に略記法があり、v-on:
は省略して@
と表記することもできる。
Appendix
Property '~' has no initializer and is not definitely assigned in the constructor
実行時に上のエラーが鬱陶しい場合、tsconfig.jsonに以下を追記すると解消する。
"strictPropertyInitialization": false
お世話になった参考サイト