12
7

More than 1 year has passed since last update.

Vue3 script setup + TypeScriptで書いてみた

Last updated at Posted at 2022-07-07

Vue.js 3.2 からscript setup構文が使えるようになり、
単一ファイルコンポーネント(SFC)内で Composition API を使用している際に使える構文となります。
https://vuejs.org/api/sfc-script-setup.html

従来の Composition API における setup() 関数の内部の記述を、
純粋なJavaScript, TypeScriptのように、script直下に単純に変数や関数等を記述できます。

今回の記事ではscript setup構文における以下を簡潔に記載します。

  • script setupの基本構文
  • componentの読み込み
  • component内のプロパティの公開方法
  • Propsの書き方
  • Emitの書き方

書き始める前に

VSCodeにおける.vue ファイルの拡張機能としてよく使われているVeturはscript setup構文には対応していません。
代わりに、Volarを使うことが推奨されています。
拡張機能を入れておきましょう。
https://marketplace.visualstudio.com/items?itemName=vue.volar

まずはscript setupの記述をする

Sample.vue
<script setup lang="ts">
import { ref } from "vue";

const text = ref<string>('hello');

</script>

<template>
    {{ text }}
</template>

従来のsetup()関数の記述の必要が無いため、非常にシンプルです。
textをバインドするためにreturnする必要もないため、従来の記法と比べて記述量が減ります。

Componentを読み込む

Parent.vue
<script setup lang="ts">
import Child from "./components/Child.vue";

</script>

<template>
    <Child />
</template>

componentsディレクトリ配下に作成したChild.vueをimportし、template内で呼び出す記述をするだけです。

Component内のプロパティを明示的に公開する

script setupを使用したコンポーネントは、デフォルトで閉じられています。
つまり、この状態ではテンプレート参照により、親から子コンポーネントの値にアクセスする事ができません。
そこで、コンポーネントのプロパティを明示的に公開するには、defineExposeコンパイラマクロを使用します。
script setupが処理されるときにコンパイルされます。

以下にChild.vueのchildMethodを明示的に公開した場合の記述をします。

  • 親componentの記載
Parent.vue
<script setup lang="ts">
const parentMethod = () => {
  childRef.value.childMethod() // コンソールに1と出力される
};
</script>

<template>
  <Child ref="childRef" />
  <button @click="parentMethod">子コンポーネント内のchildMethodを実行する</button>
</template>
  • 子componentの記載
Child.vue
<script setup lang="ts">
const a: number = 1;
const childMethod = () => {
  console.log(a);
};

defineExpose({
  childMethod
});
</script>

Propsを使う

propsを純粋なTypeScriptの構文で定義することができるようになりました。
script setupの中でpropsを宣言するには、definePropsのAPIを使用する必要があります。
definePropsは、script setup内でのみ使用可能なコンパイラマクロです。

  • 親componentの記載
Parent.vue
<script setup lang="ts">
import { ref } from "vue";
import Child from "./components/Child.vue";

const hello = ref<string>('hello');

</script>

<template>
    <Child :text="hello" />
</template>

子側でこれから定義するtextに対してhelloを渡します。

  • 子componentの記載
Child.vue
<script setup lang="ts">
import { ref } from "vue";

interface Props {
 text: string;
}

const props = defineProps<Props>();
const text = ref<string>(props.text)

</script>

<template>
    {{ text }} <!-- hello -->
</template>

props は defineProps() で定義されます。
interfaceで型定義をし、親側から渡ってきたhelloを使えるようにします。

Emitを使う

emitもpropsと同様に、TypeScriptにより型定義をすることが可能です。
script setupの中でemitを宣言するには、defineEmitsのAPIを使用する必要があります。
defineEmitsは、script setup内でのみ使用可能なコンパイラマクロです。

  • 親componentの記載
Parent.vue
<script setup lang="ts">
import Child from "./components/Child.vue";

const receiveText = (text: string) => {
 console.log(text) // コンソールにhelloと出力される
}

</script>

<template>
    <Child @emitText="receiveText" />
</template>

親側ではreceiveText関数を用意し、子から渡ってくるtextをconsole.logで見れるようにしておきます。
emitTextが発火するとreceiveTextが実行されます。
emitText発火時にtextが渡るように子側で定義すれば、receiveText内でtextを使うことができます。
それではemitTextはこれから子側で定義していきます。

  • 子componentの記載
Child.vue
<script setup lang="ts">
interface Emits {
  (e: "emitText", value: string): void;
}

const emit = defineEmits<Emits>();
const text: string = "hello"
const clickBtn = () => {
 emit("emitText", text)
}

</script>

<template>
    <button @click="clickBtn">ボタン</button>
</template>

上記の場合、ボタンをクリックすると、clickBtnが実行され、emitTextが発火し、textを親側へ渡します。

まとめ

まずはこの基本的な書き方ができれば、大方従来の書き方からscript setup構文に切り替える事はできるでしょう。
scirpt setup導入編として、少しでも参考にいただけますと幸いです。

12
7
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
12
7