Skip to content

Commit 290e4a4

Browse files
naokihabajay-es
andauthored
docs: 3.5: useTemplateRef() (#2311)
* docs: Update usage of `useTemplateRef()` in composition API guide * docs: Update usage of `useTemplateRef()` in composition API guide * feat: Update usage of `useTemplateRef()` in composition API guide * Update src/guide/typescript/composition-api.md Co-authored-by: Jun Shindo <[email protected]> * Update src/guide/typescript/composition-api.md Co-authored-by: Jun Shindo <[email protected]> * Update src/guide/typescript/composition-api.md Co-authored-by: Jun Shindo <[email protected]> * Update src/guide/typescript/composition-api.md Co-authored-by: Jun Shindo <[email protected]> --------- Co-authored-by: Jun Shindo <[email protected]>
1 parent 4d8ae05 commit 290e4a4

File tree

2 files changed

+109
-27
lines changed

2 files changed

+109
-27
lines changed

src/guide/essentials/template-refs.md

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,31 @@ Vue の宣言型レンダリングモデルは、直接的な DOM 操作のほ
1212

1313
<div class="composition-api">
1414

15-
Composition API で参照を取得するには、以下のようにテンプレートの ref 属性の値と一致する名前の ref を宣言します:
15+
Composition API で参照を取得するには、[`useTemplateRef()`](/api/composition-api-helpers#usetemplateref) ヘルパー <sup class="vt-badge" data-text="3.5+" /> を使用できます:
16+
17+
```vue
18+
<script setup>
19+
import { useTemplateRef, onMounted } from 'vue'
20+
21+
// 最初の引数は、テンプレートの ref の値に一致させる必要があります。
22+
const input = useTemplateRef('my-input')
23+
24+
onMounted(() => {
25+
input.value.focus()
26+
})
27+
</script>
28+
29+
<template>
30+
<input ref="my-input" />
31+
</template>
32+
```
33+
34+
TypeScript を使用する場合、Vue の IDE サポートと `vue-tsc` は、一致する `ref` 属性が使用されている要素やコンポーネントに基づいて、`inputRef.value` の型を自動的に推論します。
35+
36+
<details>
37+
<summary>3.5 以前の使用方法</summary>
38+
39+
`useTemplateRef()` が導入されていなかった 3.5 以前のバージョンでは、テンプレート内の `ref` 属性の値と同じ名前で `ref` を宣言する必要がありました:
1640

1741
```vue
1842
<script setup>
@@ -46,6 +70,8 @@ export default {
4670
}
4771
```
4872

73+
</details>
74+
4975
</div>
5076
<div class="options-api">
5177

@@ -95,6 +121,33 @@ watchEffect(() => {
95121

96122
`v-for` の中で `ref` を使用すると、対応する参照には配列値が格納されます。そしてこの配列値には、マウント後の要素が代入されます:
97123

124+
```vue
125+
<script setup>
126+
import { ref, useTemplateRef, onMounted } from 'vue'
127+
128+
const list = ref([
129+
/* ... */
130+
])
131+
132+
const itemRefs = useTemplateRef('items')
133+
134+
onMounted(() => console.log(itemRefs.value))
135+
</script>
136+
137+
<template>
138+
<ul>
139+
<li v-for="item in list" ref="items">
140+
{{ item }}
141+
</li>
142+
</ul>
143+
</template>
144+
```
145+
146+
[Playground で試す](https://play.vuejs.org/#eNp9UsluwjAQ/ZWRLwQpDepyQoDUIg6t1EWUW91DFAZq6tiWF4oU5d87dtgqVRyyzLw3b+aN3bB7Y4ptQDZkI1dZYTw49MFMuBK10dZDAxZXOQSHC6yNLD3OY6zVsw7K4xJaWFldQ49UelxxVWnlPEhBr3GszT6uc7jJ4fazf4KFx5p0HFH+Kme9CLle4h6bZFkfxhNouAIoJVqfHQSKbSkDFnVpMhEpovC481NNVcr3SaWlZzTovJErCqgydaMIYBRk+tKfFLC9Wmk75iyqg1DJBWfRxT7pONvTAZom2YC23QsMpOg0B0l0NDh2YjnzjpyvxLrYOK1o3ckLZ5WujSBHr8YL2gxnw85lxEop9c9TynkbMD/kqy+svv/Jb9wu5jh7s+jQbpGzI+ZLu0byEuHZ+wvt6Ays9TJIYl8A5+i0DHHGjvYQ1JLGPuOlaR/TpRFqvXCzHR2BO5iKg0Zmm/ic0W2ZXrB+Gve2uEt1dJKs/QXbwePE)
147+
148+
<details>
149+
<summary>3.5 以前の使用方法</summary>
150+
98151
```vue
99152
<script setup>
100153
import { ref, onMounted } from 'vue'
@@ -117,7 +170,7 @@ onMounted(() => console.log(itemRefs.value))
117170
</template>
118171
```
119172

120-
[Playground で試す](https://play.vuejs.org/#eNpFjs1qwzAQhF9l0CU2uDZtb8UOlJ576bXqwaQyCGRJyCsTEHr3rGwnOehnd2e+nSQ+vW/XqMSH6JdL0J6wKIr+LK2evQuEhKCmBs5+u2hJ/SNjCm7GiV0naaW9OLsQjOZrKNrq97XBW4P3v/o51qTmHzUtd8k+e0CrqsZwRpIWGI0KVN0N7TqaqNp59JUuEt2SutKXY5elmimZT9/t2Tk1F+z0ZiTFFdBHs738Mxrry+TCIEWhQ9sttRQl0tEsK6U4HEBKW3LkfDA6o3dst3H77rFM5BtTfm/P)
173+
</details>
121174

122175
</div>
123176
<div class="options-api">
@@ -173,6 +226,26 @@ export default {
173226

174227
<div class="composition-api">
175228

229+
```vue
230+
<script setup>
231+
import { useTemplateRef, onMounted } from 'vue'
232+
import Child from './Child.vue'
233+
234+
const childRef = useTemplateRef('child')
235+
236+
onMounted(() => {
237+
// child.value は <Child /> のインスタンスを保持します。
238+
})
239+
</script>
240+
241+
<template>
242+
<Child ref="child" />
243+
</template>
244+
```
245+
246+
<details>
247+
<summary>3.5 以前の使用方法</summary>
248+
176249
```vue
177250
<script setup>
178251
import { ref, onMounted } from 'vue'
@@ -190,6 +263,8 @@ onMounted(() => {
190263
</template>
191264
```
192265

266+
</details>
267+
193268
</div>
194269
<div class="options-api">
195270

src/guide/typescript/composition-api.md

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,17 @@ const foo = inject('foo') as string
371371

372372
## テンプレート参照の型付け {#typing-template-refs}
373373

374+
Vue 3.5 と `@vue/language-tools` 2.1(IDE の言語サービスと `vue-tsc` の両方をサポート)では、SFC の `useTemplateRef()` で作成された `ref` の型は、`ref` 属性が使用されている要素またはコンポーネントに基づいて、静的な `ref` の型を**自動的に推論**できます。
375+
376+
自動推論が不可能な場合でも、ジェネリック引数を使用してテンプレート参照を明示的な型にキャストすることができます:
377+
378+
```ts
379+
const el = useTemplateRef<HTMLInputElement>(null)
380+
```
381+
382+
<details>
383+
<summary>3.5 以前の使用方法</summary>
384+
374385
テンプレート参照は、明示的な型引数と初期値 `null` を指定して作成されます:
375386

376387
```vue
@@ -389,50 +400,45 @@ onMounted(() => {
389400
</template>
390401
```
391402

403+
</details>
404+
392405
適切な DOM インターフェースを取得するには、[MDN](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input#技術的概要) のようなページを確認してください。
393406

394407
厳密な型安全性のために、`el.value` にアクセスする際には、オプショナルチェーンもしくは型ガードをする必要があります。なぜなら、コンポーネントがマウントされるまでは ref の初期値は `null` であり、参照されていた要素が `v-if` によってアンマウントされた場合にも `null` にセットされる可能性があるからです。
395408

396409
## コンポーネントのテンプレート参照の型付け {#typing-component-template-refs}
397410

398-
時に、子コンポーネントのパブリックメソッドを呼ぶために、子コンポーネントのテンプレート参照に型づけする必要があるかもしれません。例えば、モーダルを開くメソッドを持つ `MyModal` という子コンポーネントがあるとします:
399-
400-
```vue
401-
<!-- MyModal.vue -->
402-
<script setup lang="ts">
403-
import { ref } from 'vue'
404-
405-
const isContentShown = ref(false)
406-
const open = () => (isContentShown.value = true)
411+
Vue 3.5 と `@vue/language-tools` 2.1(IDE の言語サービスと `vue-tsc` の両方をサポート)では、SFC の `useTemplateRef()` で作成された `ref` の型は、`ref` 属性が使用されている要素またはコンポーネントに基づいて、静的な `ref` の型を**自動的に推論**できます。
407412

408-
defineExpose({
409-
open
410-
})
411-
</script>
412-
```
413+
自動推論が不可能な場合(例えば、SFC 以外の使用や動的コンポーネントの場合)でも、ジェネリック引数を使用してテンプレート参照を明示的な型にキャストすることができます。
413414

414-
`MyModal` のインスタンスの型を得るために、まず `typeof` によって型を取得し、次に TypeScript の組み込みユーティリティーの `InstanceType` を使って型を抽出する必要があります:
415+
インポートされたコンポーネントのインスタンスの型を得るために、まず `typeof` によって型を取得し、次に TypeScript の組み込みユーティリティーの `InstanceType` を使って型を抽出する必要があります:
415416

416417
```vue{5}
417418
<!-- App.vue -->
418419
<script setup lang="ts">
419-
import MyModal from './MyModal.vue'
420+
import { useTemplateRef } from 'vue'
421+
import Foo from './Foo.vue'
422+
import Bar from './Bar.vue'
420423
421-
const modal = ref<InstanceType<typeof MyModal> | null>(null)
424+
type FooType = InstanceType<typeof Foo>
425+
type BarType = InstanceType<typeof Bar>
422426
423-
const openModal = () => {
424-
modal.value?.open()
425-
}
427+
const compRef = useTemplateRef<FooType | BarType>('comp')
426428
</script>
429+
430+
<template>
431+
<component :is="Math.random() > 0.5 ? Foo : Bar" ref="comp" />
432+
</template>
427433
```
428434

429435
コンポーネントの正確な型がわからない場合や重要でない場合は、代わりに `ComponentPublicInstance` を使用できます。この場合、`$el` のようなすべてのコンポーネントで共有されているプロパティのみが含まれます:
430436

431437
```ts
432-
import { ref } from 'vue'
438+
import { useTemplateRef } from 'vue'
433439
import type { ComponentPublicInstance } from 'vue'
434440

435-
const child = ref<ComponentPublicInstance | null>(null)
441+
const child = useTemplateRef<ComponentPublicInstance | null>(null)
436442
```
437443

438444
参照されるコンポーネントが[ジェネリックコンポーネント](/guide/typescript/overview.html#generic-components)の場合、例えば `MyGenericModal` の場合:
@@ -457,15 +463,16 @@ defineExpose({
457463
```vue
458464
<!-- App.vue -->
459465
<script setup lang="ts">
466+
import { useTemplateRef } from 'vue'
460467
import MyGenericModal from './MyGenericModal.vue'
468+
import type { ComponentExposed } from 'vue-component-type-helpers'
461469
462-
import type { ComponentExposed } from 'vue-component-type-helpers';
463-
464-
const modal = ref<ComponentExposed<typeof MyModal> | null>(null)
470+
const modal = useTemplateRef<ComponentExposed<typeof MyGenericModal>>(null)
465471
466472
const openModal = () => {
467473
modal.value?.open('newValue')
468474
}
469475
</script>
470476
```
471477

478+
なお、`@vue/language-tools` 2.1 以降では、静的テンプレート参照の型は自動的に推論されるので、上記はエッジケースでのみ必要となります。

0 commit comments

Comments
 (0)