From e1f4efba1b0de0f101b85c710af61f6c5d197bad Mon Sep 17 00:00:00 2001 From: Ubugeeei Date: Fri, 6 Sep 2024 21:07:23 +0900 Subject: [PATCH] feat: 1.vue/5.components --- .../files/{ChildComponent.vue => Child.vue} | 0 .../5.components/.template/files/app.vue | 6 +- .../{ChildComponent.vue => Child.vue} | 14 +- .../5.components/.template/solutions/app.vue | 24 +++- content/1.vue/5.components/index.md | 128 ++++++++++++++---- 5 files changed, 136 insertions(+), 36 deletions(-) rename content/1.vue/5.components/.template/files/{ChildComponent.vue => Child.vue} (100%) rename content/1.vue/5.components/.template/solutions/{ChildComponent.vue => Child.vue} (54%) diff --git a/content/1.vue/5.components/.template/files/ChildComponent.vue b/content/1.vue/5.components/.template/files/Child.vue similarity index 100% rename from content/1.vue/5.components/.template/files/ChildComponent.vue rename to content/1.vue/5.components/.template/files/Child.vue diff --git a/content/1.vue/5.components/.template/files/app.vue b/content/1.vue/5.components/.template/files/app.vue index 85b7e10..d5fc2fe 100644 --- a/content/1.vue/5.components/.template/files/app.vue +++ b/content/1.vue/5.components/.template/files/app.vue @@ -1,5 +1,5 @@ diff --git a/content/1.vue/5.components/.template/solutions/app.vue b/content/1.vue/5.components/.template/solutions/app.vue index 8bfd556..5781e55 100644 --- a/content/1.vue/5.components/.template/solutions/app.vue +++ b/content/1.vue/5.components/.template/solutions/app.vue @@ -1,16 +1,30 @@ + + diff --git a/content/1.vue/5.components/index.md b/content/1.vue/5.components/index.md index a4d6fb4..a00212c 100644 --- a/content/1.vue/5.components/index.md +++ b/content/1.vue/5.components/index.md @@ -9,7 +9,7 @@ Vue.js のコンポーネントは、UI を小さな再利用可能な部分に ## 基本的な SFC の構造 -SFC は基本的に以下のような ` ``` @@ -60,58 +60,136 @@ import ChildComponent from './ChildComponent.vue' Vue コンポーネント間でデータをやり取りする基本的な方法として、`props` と `emit` を使用します。 -- `props`: 親コンポーネントから子コンポーネントにデータを渡すための方法です。 -- `emit`: 子コンポーネントから親コンポーネントにイベントを発火するための方法です。 +### Props -それぞれ `defineProps`, `defineEmits` で登録します。\ -使い方は右側のプレイグラウンド、または [API ドキュメント](https://ja.vuejs.org/api/sfc-script-setup.html#defineprops-defineemits)から確認できます。 +親コンポーネントから子コンポーネントにデータを渡すための方法です。 -## 双方向バインディング - -コンポーネント上で `v-model` を使うことで双方向バインディングを実装できます。\ -以下の例では、コンポーネント中で宣言された `value` が `` の値とバインドされ、`` の入力値が `value` に反映されます。 +まずは子コンポーネント側で `defineProps` マクロを使用し、受け取りたいデータを定義します。 ```vue + +``` +次に親コンポーネント側で、子コンポーネントにデータを渡すために `v-bind` ディレクティブを使用します。\ +`:props名="データ"` という形式で、子コンポーネントにデータを渡すことができます。 + +```vue + ``` -また、SFC で `defineModel` を使うことで、親コンポーネントから `v-model` 経由で使用できる双方向バインディングの `props` を宣言できます。 +また、props 名とデータの変数名が同名の場合は省略記法を使うことができます。 + +```vue + + +``` + +### Emit + +子コンポーネントから親コンポーネントにイベントを発火するための方法です。 + +まずは子コンポーネント側で `defineEmits` マクロを使用し、発火したいイベントを定義します。 +emit 関数を用いて、イベントを発火することができます。 ```vue ``` +発火されたイベントは親コンポーネント側で `v-on` ディレクティブを使用して受け取ることができます。 + ```vue -const parentValue = ref('Initial Value') + +``` + +以下のように、イベント発火時に子コンポーネントからデータを受け渡すこともできます。 + +```vue + + ``` -## チャレンジ +```vue + + -プレイグラウンドの `ChildComponent.vue` は `props` と `emit` を使って双方向バインディングを実現しています。\ -これを `defineModel` を使って簡潔に書き直してみましょう。 + +``` -もし手詰まりになったら、解決策を確認するためのボタンをクリックして、ヒントを得ることができます。 +それぞれの詳しい [API ドキュメント](https://ja.vuejs.org/api/sfc-script-setup.html#defineprops-defineemits)から確認することができます。 + +## チャレンジ -:ButtonShowSolution{.bg-faded.px4.py2.rounded.border.border-base.hover:bg-active.hover:text-primary.hover:border-primary:50} +右のプレイグラウンドでは、props と emit を使ってコンポーネント間のデータの受け渡しを行っています。\ +Vue.js では [スロット](https://ja.vuejs.org/guide/components/slots.html) という機能を利用することで、親コンポーネントからコンポーネントにテンプレートを挿入することができます。\ +右のプレイグラウンドを編集して、スロットを使ったテンプレートの挿入を行ってみましょう。 + +1. 子コンポーネント (`Child.vue`) でスロットの定義を行う\ + [defineSlot マクロ](https://ja.vuejs.org/api/sfc-script-setup.html#defineslots) を使うことにより、型安全なスロットを定義することができます。\ + 定義ができたら、template 内で `slot` タグを配置することで渡されたテンプレートの挿入を行うことができます。 + + ```vue + + + + ``` + +2. 親コンポーネント (`app.vue`) で slot にテンプレートを挿入する\ + 親コンポーネント側で、子コンポーネントにテンプレートを挿入するために `v-slot` ディレクティブを使用します。\ + (ここでは `v-slot` の省略記法である `#` を使用しています) + + ```vue + + ``` + + :ButtonShowSolution{.bg-faded.px4.py2.rounded.border.border-base.hover:bg-active.hover:text-primary.hover:border-primary:50}