はじめに
「今後はフロントエンドを担当してもらうから」
上司から突然告げられたジョブチェンジ。
まだまだPHPの経験値が足りないから基礎からしっかりやっていこうと思っていたタイミングで宣告だったので、 「まじか〜〜!」って感じでしたが、従うしかない。
これが社会。
人がいないから仕方がない。
自分は1年ほど前に少しJavaScriptを学んでいましたが、「jQueryって簡単に動きつけられるし、すげ〜〜」レベル。
フレームワークを学んだこともなければ、コンポーネントについても理解していない。
しかし、その前にTypeScriptもやらねばいけない。
そんなこんなで、日々頭がオーバーヒートしかけながらなんとか戦っています。
駆け出しバックエンドエンジニアが(ほぼ)未経験からフロントエンドエンジニアとして戦えるようになるまで学んだことを記録してやろうと思っています。
今回は初回なのでざっとまとめてみた。
コンポーネントの作り方
コンポーネント:機能を持ったHTML要素の設計図
コンポーネントの基本構成
下記のサンプルコードを参照にされたし。
<template> <div class="my-component"> <h1>{{ title }}</h1> <input v-model="inputText" placeholder="Enter text" /> <button @click="handleClick">Submit</button> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ name: 'MyComponent', data() { return { title: 'My Vue Component', inputText: '' }; }, methods: { handleClick() { console.log(this.inputText); } } }); </script> <style scoped> .my-component { text-align: center; } button { margin-top: 10px; } </style>
基本的には、
- template
- script
- style
の3つで構成されている。
<template></template>
部分
ここに書かれたHTMLがブラウザ上に表示される。
<script></script>
部分
コンポーネントのロジックを定義する部分で、データやメソッド、ライフサイクルフック、コンポーネントの設定などを定義する。 オブジェクトベースとクラスベースがある。
オブジェクトベース
<script> export default { name: 'MyComponent`, props: { title: { type: String, required: true } }, data() { return { count: 0 } }, methods: { handleClick() { this.$emit('clicked', this.count++) } } } </script>
クラスベース
ぺんカルはこっち。 ES6のクラス構文を使って定義する。
<script lang='ts'> import { Vue, Component, Prop, Emit } from 'vue-property-decorator' @Component export default class MyComponent extends Vue { @Props({ required: true }) readonly title!: string count: number = 0 @Emit('clicked') handleClick() { this.count++ return this.count } } </script>
<style></style>
部分
コンポーネントのスタイリングをする。
デコレータ
@Emit
や@Prop
の@
はデコレータで、クラスやクラスのメソッド、プロパティに対して動作を付与するもの。
@Prop
import { Vue, Component, Prop } from 'vue-propertiy-decorator' @Component export default MyComponent extends Vue { @Prop({ type: String, required: true }) title: string }
上記のコードはtitle
というプロパティを親コンポーネントから受け取ることができる。
@Emit
メソッドが実行された際にVueイベントを発火する。
import { Vue, Component, Emit } from 'vue-property-decorator' @Component export default class MyComponent extends Vue { @Emit('submit') handleSubmit() { return 'data to emit' } }
handleSubmit
メソッドが呼ばれると、Submitイベントが自動で発火されて親コンポーネントに追加される。
親コンポーネントと子コンポーネント
ここがまーじでわからんので理解していく。
親 → 子: Props
でデータを渡す→親コンポーネントは子コンポーネントにProps
を使ってデータを渡す。
子 → 親:イベントでデータを返す→子コンポーネントは$emit
を使ってイベントを発火し、親コンポーネントにデータやイベントを通知する。
サンプルコード
// 親コンポーネント <template> <div> <h1>親コンポーネント</h1> <!-- 子コンポーネントへ "message" という Prop を渡す --> <ChildComponent :message="parentMessage" @updateMessage="handleUpdateMessage" /> <p>子からのメッセージ: {{ childMessage }}</p> </div> </template> <script lang="ts"> import { Component, Vue } from "vue-property-decorator"; import ChildComponent from './ChildComponent.vue'; @Component({ components: { ChildComponent } }) export default class ParentComponent extends Vue { parentMessage: string = '親からのメッセージ'; childMessage: string = ''; // 子コンポーネントから受け取ったメッセージを処理 handleUpdateMessage(newMessage: string) { this.childMessage = newMessage; } } </script>
// 子コンポーネント <template> <div> <h2>子コンポーネント</h2> <!-- 親から受け取った Props の表示 --> <p>親からのメッセージ: {{ message }}</p> <button @click="sendMessageToParent">親へメッセージを送る</button> </div> </template> <script lang="ts"> import { Component, Vue, Prop, Emit } from "vue-property-decorator"; @Component export default class ChildComponent extends Vue { // 親から渡された message プロパティを受け取る @Prop({ required: true }) message!: string; // 親にメッセージを送るためのメソッド @Emit('updateMessage') sendMessageToParent() { return '子からの新しいメッセージ'; } } </script>
親と子をどうやって判断するか
親の特徴:他のコンポーネントを使用している、データを渡している、イベントをリッスンしている
子の特徴:props
を受け取っている、イベントを発火している
つまり、下記のように判断できる
- テンプレート内で子コンポーネンが使われているかどうか
props
とemit
どちらを使っているか