Skip to content
This repository was archived by the owner on May 25, 2024. It is now read-only.

Commit b1e1ffd

Browse files
committed
feat: use defineSlots
1 parent e5c0f30 commit b1e1ffd

File tree

2 files changed

+70
-69
lines changed

2 files changed

+70
-69
lines changed

packages/app/src/components/Card.vue

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
defineProps<{ name: string, price: number, image: string }>()
3+
defineSlots<{ body: () => any }>()
34
45
/** 価格を3桁ごとのカンマ付きで返す */
56
function pricePrefix(price: number): string {

packages/docs/src/slot.md

+69-69
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# コンポーネントにスロットを使用する
22

3-
商品をコンポーネント化したことで、`Card` コンポーネントに必要な情報を `props` で渡すだけとなり、コードが見やすくなりました
3+
商品をコンポーネント化したことで、`Card` コンポーネントに必要な情報を `props` で渡すだけとなり、コードが見やすくなり、再利用性も向上しました
44

55
```vue
66
<template>
@@ -35,13 +35,15 @@
3535

3636
### スロットとは
3737

38-
Vue.js のスロットでは、親コンポーネントから子コンポーネントにコンテンツを渡してレンダリングすることが可能です。スロットを使用すると、コンポーネントの `props` の修正に手を入れることなく、表示するコンテンツを変更できるため、コンポーネントの再利用性と柔軟性が高まります。スロットには、**スロットコンテンツ****スロットアウトレット**という仕組みがあるので、説明していきます。
38+
Vue.js のスロットでは、親コンポーネントから子コンポーネントにコンテンツを渡してレンダリングすることが可能です。\
39+
スロットを使用するとことによって親コンポーネントからレンダリングしたいコンテンツを挿入できるため、コンポーネントの再利用性と柔軟性が高まります。
3940

4041
#### スロットコンテンツ
4142

4243
スロットコンテンツとは、子コンポーネントへ渡すコンテンツのことを指します。
4344

44-
コンテンツを渡す方法は、親コンポーネントで子コンポーネントを呼び出し、子コンポーネントの要素へレンダリングしたいコンテンツを定義します。スロットコンテンツとして、プレーンテキスト、HTML 要素、他のコンポーネントなど、さまざまな種類を渡すことができます。
45+
コンテンツを渡す方法は、親コンポーネントで子コンポーネントを呼び出し、子コンポーネントの要素へレンダリングしたいコンテンツを定義します。\
46+
スロットコンテンツとして、プレーンテキスト、HTML 要素、他のコンポーネントなど、さまざまな種類を渡すことができます。
4547

4648
#### 親コンポーネント
4749

@@ -54,21 +56,25 @@ Vue.js のスロットでは、親コンポーネントから子コンポーネ
5456
#### スロットアウトレット
5557

5658
親コンポーネントでスロットコンテンツを定義しましたが、子コンポーネント側では、スロットコンテンツを受け取るためのスロットアウトレットを用意する必要があります。
57-
58-
コンテンツを受け取る方法は、スロットコンテンツをレンダリングしたい場所に `slot` 要素を定義します。
59+
コンテンツを受け取る方法は、スロットコンテンツをレンダリングしたい場所に `slot` 要素を定義します。\
60+
また、`defineSlots` マクロを利用することで型定義を行うことができます。(親コンポーネント側でエディタの支援や型チェックを行えるようになります。)
5961

6062
#### 子コンポーネント
6163

6264
```vue
63-
<div>
64-
<!-- 親要素のスロットコンテンツがslot要素へレンダリングされる -->
65+
<script setup lang="ts">
66+
defineSlots<{ default: () => any }>() // default については後述
67+
</script>
68+
69+
<template>
70+
<!-- 親要素のスロットコンテンツが slot 要素へレンダリングされる -->
6571
<slot />
66-
</div>
72+
</template>
6773
```
6874

6975
スロットコンテンツで紹介した親コンポーネントのコードと、スロットアウトレットの子コンポーネントを組み合わせると、最終的に表示されるコードは以下のようになります。
7076

71-
```vue
77+
```html
7278
<div>
7379
<!-- スロットコンテンツがスロットアウトレットにレンダリングされている -->
7480
スロットコンテンツ
@@ -84,6 +90,13 @@ Vue.js のスロットでは、親コンポーネントから子コンポーネ
8490
#### 子コンポーネント
8591

8692
```vue
93+
<script setup lang="ts">
94+
defineSlots<{
95+
contents: () => any
96+
footer: () => any
97+
}>()
98+
</script>
99+
87100
<template>
88101
<div>
89102
<h2>Child Component</h2>
@@ -104,6 +117,7 @@ Vue.js のスロットでは、親コンポーネントから子コンポーネ
104117
<template #contents>
105118
<p>コンテンツ</p>
106119
</template>
120+
107121
<template #footer>
108122
<p>フッター</p>
109123
</template>
@@ -184,26 +198,8 @@ Vue.js のスロットでは、親コンポーネントから子コンポーネ
184198

185199
### スロットを利用し、テキストを挿入する
186200

187-
`Card` コンポーネントでは、`name` 属性に `body` を指定したスロットアウトレットを定義します。同時に、`props` から `description` を削除しておきます。
188-
189-
#### Card.vue / template
190-
191-
```vue{9}
192-
<template>
193-
<div class="thumbnail">
194-
<img
195-
:src="image"
196-
alt="">
197-
</div>
198-
<div class="description">
199-
<h2>{{ name }}</h2>
200-
<slot name="body" />
201-
<span>¥<span class="price">{{ pricePrefix(price) }}</span></span>
202-
</div>
203-
</template>
204-
```
205-
206-
#### Card.vue / script
201+
`Card` コンポーネントでは、`name` 属性に `body` を指定したスロットアウトレットを定義します。\
202+
`props` からは `description` を削除しておきます。
207203

208204
```vue
209205
<script setup lang="ts">
@@ -212,9 +208,24 @@ defineProps<{
212208
image: string
213209
name: string
214210
price: number
211+
description: string // [!code --]
215212
}>()
216-
// 省略
213+
214+
defineSlots<{ // [!code ++]
215+
body: () => any // [!code ++]
216+
}>() // [!code ++]
217217
</script>
218+
219+
<template>
220+
<div class="thumbnail">
221+
<img :src="image" alt="">
222+
</div>
223+
<div class="description">
224+
<h2>{{ name }}</h2>
225+
<slot name="body" /> <!-- [!code ++] -->
226+
<span>¥<span class="price">{{ pricePrefix(price) }}</span></span>
227+
</div>
228+
</template>
218229
```
219230

220231
以上で、スロットの置き換えが完了です。見た目上の変化はありませんが、`body` のスロットコンテンツが表示されているかと思います。
@@ -231,7 +242,7 @@ defineProps<{
231242

232243
#### App.vue / script
233244

234-
```vue{15}
245+
```vue
235246
<script setup lang="ts">
236247
import { ref } from 'vue'
237248
import Card from './components/Card.vue'
@@ -246,9 +257,9 @@ const items = ref([
246257
image: '/images/item1.jpg',
247258
soldOut: false,
248259
selected: false,
249-
link: 'https://handson.vuejs-jp.org/'
260+
link: 'https://handson.vuejs-jp.org/' // [!code ++]
250261
},
251-
//省略
262+
// 省略
252263
])
253264
</script>
254265
```
@@ -260,16 +271,16 @@ const items = ref([
260271
```vue{10}
261272
<template>
262273
<!-- 省略-->
263-
<Card
264-
:id="item.id"
265-
:image="item.image"
266-
:name="item.name"
267-
:price="item.price">
268-
<template #body>
269-
<p>{{ item.description }}</p>
270-
<a v-if="item.link" :href="item.link">リンク</a>
271-
</template>
272-
</Card>
274+
<Card
275+
:id="item.id"
276+
:image="item.image"
277+
:name="item.name"
278+
:price="item.price">
279+
<template #body>
280+
<p>{{ item.description }}</p>
281+
<a v-if="item.link" :href="item.link">リンク</a> <!-- [!code ++] -->
282+
</template>
283+
</Card>
273284
<!-- 省略-->
274285
</template>
275286
```
@@ -286,18 +297,7 @@ const items = ref([
286297

287298
```vue
288299
<script setup lang="ts">
289-
defineProps({
290-
description: {
291-
type: String,
292-
default: '',
293-
required: false
294-
},
295-
link: {
296-
type: String,
297-
default: '',
298-
required: false
299-
}
300-
})
300+
defineProps<{ description: string, link: string }>()
301301
</script>
302302
303303
<template>
@@ -314,25 +314,25 @@ defineProps({
314314
<script setup lang="ts">
315315
import { ref } from 'vue'
316316
import Card from './components/Card.vue'
317-
import CardBody from './components/CardBody.vue';
317+
import CardBody from './components/CardBody.vue'; // [!code ++]
318318
319-
//省略
319+
// 省略
320320
</script>
321321
322322
<template>
323323
<!-- 省略-->
324-
<Card
325-
:id="item.id"
326-
:image="item.image"
327-
:name="item.name"
328-
:description="item.description"
329-
:price="item.price">
330-
<template #body>
331-
<CardBody
332-
:description="item.description"
333-
:link="item.link"/>
334-
</template>
335-
</Card>
324+
<Card
325+
:id="item.id"
326+
:image="item.image"
327+
:name="item.name"
328+
:description="item.description"
329+
:price="item.price">
330+
<template #body>
331+
<p>{{ item.description }}</p> <!-- [!code --] -->
332+
<a v-if="item.link" :href="item.link">リンク</a> <!-- [!code --] -->
333+
<CardBody :description="item.description" :link="item.link" /> <!-- [!code ++] -->
334+
</template>
335+
</Card>
336336
<!-- 省略-->
337337
</template>
338338
```

0 commit comments

Comments
 (0)