0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

簡単なForm作成から学ぶVue(TypeScript)の書き方 その1

Posted at

vueコンポーネントを作成する。

〜contents〜

  • PropとEmit
  • v-bindとv-on

コンポーネントとは?

Vueでは、各機能の最小単位の部品をコンポーネントとして創り、必要な各箇所でその部品を組み合わせてページを作っていく。
今回のFormの例では、子コンポーネントはテキスト入力の部品コンポーネントやボタンの部品コンポーネントが相当し、これらを束ねるFormコンポーネントが親コンポーネントという関係になる。

image.png

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コンポーネントからは知れないし、ボタンのコンポーネントは入力値に基づいた活性非活性を分岐することはできない。

そこで、各コンポーネント間で値の授受や、関数コールを行う仕組みを利用する。それがPropEmitである。

重要なことはこれらは一方向の関係であること。
Propは親コンポーネントから子コンポーネントへ値を渡す時に使用し、Emitはこコンポーネントから親コンポーネントの関数をコールする時に使用する。(逆に、子は親の変数を直接変えないし、親が子の関数は動かさない。)

まとめ

Prop:親→子へのデータ受け渡し
Emit:子→親へのデータ受け渡し

つくってみる

ここでは、TextBoxに入力があったらボタンを活性にするFormを作る。

image.png

流れは、TextBoxコンポーネントで入力されたことをトリガにFormコンポーネントへEmitして値が入力されたことを通知する。次に、FormコンポーネントではPropを用いてButtonコンポーネントの活性を変更する。

まずは、Propv-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コンポーネントが使えるようにならないといけないのでインポートする。

親コンポーネント(Form)
//インポート
import Button from '@/components/Button.vue'

//コンポーネントの定義
@Component({
  components:{
    Button
  }
})
export default class Form extends Vue {
  private disabled: boolean = false //親コンポーンネントの変数。
}

親コンポーネントからButtonコンポーネントのdisableに値を渡してあげる。この時、渡す対象の子コンポーネントの値にはv-bind:を付して、呼び出す際に値を指定する。

親コンポーネント(Form)
    <Button v-bind:disabled="disabled"/>

上記のケースでは、ボタンが使用可能かを示すdisabledv-bind:が付され、代入される「disable」は定数ではなく、親コンポーネントのdisabledという変数である。なお、v-bind:は省略して:と表記することもできる。

親から指定されるとdisableにより子コンポーネントのclassdisabled: false指定され、disableスタイルが外れる。

<button class="button" :class="{disabled: disabled}">決定</button>

なお、<button class="button" :class="{disabled}">決定</button>としても同じ。

まとめ

変数を渡す方法
<コンポーネント名 v-bind:子コンポーネントの変数="親コンポーネントの変数" />

変数を受け取る方法
@Prop()
//子コンポーネントの変数定義

次にEmitv-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

お世話になった参考サイト

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?