setup構文で書くVue.js
はじめに
初めまして。
今回、初めてこちらに記事を書かせていただきますWatatakuと申します。
よろしくお願いします。
<script setup>
構文とは?
Vue.jsの3.2から使えるようになった記法です。
<script setup>
は単一ファイルコンポーネント(SFC)内で Composition API を使用するコンパイル時のシンタックスシュガー(糖衣構文)です。SFC と Composition API の両方を使うならば、おすすめの構文です。
VSCode 拡張機能
VSCode における .vue ファイルの拡張機能としてVeturがよく使われていたかと思われますが、 <script setup>
構文には対応していません。
なので代わりに、Volarを使うことが推奨されています。
基本の構文
<script setup>
構文を解説する前に従来のVue.jsのコードを見ていきましょう。
- Options API
<template>
<div>
<h1>{{ count }}</h1>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
data() {
return {
count: 0,
};
},
methods: {
increment() {
this.count++;
},
decrement() {
this.count--;
},
},
});
</script>
- Composition API
<template>
<h1>{{ count }}</h1>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
return {
count,
increment,
decrement,
};
},
});
</script>
簡単なカウンターアプリのコードです。
では、次に<script setup>
構文です。
<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
</script>
<template>
<h1>{{ count }}</h1>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</template>
かなりシンプルになっています。
<script setup>
構文をざっくりと説明すると、従来の Composition API における setup() 関数内部を <script>
直下に直接記述することができるという構文です。
-
<script setup>
構文ではexport default で Vue.js のオブジェクトを export する必要がなくなる - Composition API では、setup() 関数内で定義した変数や関数を return しないと
<template>
内で使用することができなかったが、<script setup>
内で宣言した場合すべて使用可能となる
コンポーネント
今まで components
に import したコンポーネントの一覧を登録しなければいけなかったのですが、import するだけで直接使えるようになりました。
- 今まで
<template>
<TheHeader />
<main>main</main>
<TheFooter />
</template>
<script lang="ts">
import TheHeader from "./components/TheHeader.vue";
import TheFooter from "./components/TheFooter.vue";
export default defineComponent({
component: {
TheHeader,
TheFooter
}
});
</script>
-
<script setup>
構文
<script lang="ts" setup>
import TheHeader from "./components/TheHeader.vue";
import TheFooter from "./components/TheFooter.vue";
</script>
<template>
<TheHeader />
<main>main</main>
<TheFooter />
</template>
propsとemit
props
<script setup>
構文でpropsを扱うときはdefineProps
を使います。
<script setup lang="ts">
type Props {
value: string;
label?: string;
type?: "text" | "password" | "email" | "number";
placeholder?: string;
disabled?: boolean;
}
defineProps<Props>();
</script>
<template>
<label>
{{ label }}
<input
:value="value"
:type="type"
:placeholder="placeholder"
:disabled="disabled"
/>
</label>
</template>
props のデフォルト値を定義する場合には、 withDefaults
を使用します。
withDefaults(defineProps<Props>(), {
label: "",
type: "text",
placeholder: "",
disabled: false,
});
emit
<script setup>
構文でemitを扱うときはdefineEmits
を使います。
emit も props と同様に、TypeScriptにより型定義をすることが可能です。
type Emits = {
(e: "Emitの名前", 渡したい引数: 型): void
(e: "Emitの名前2", 渡したい引数: 型): void
}
defineEmits<Emits>();
では、具体的な扱い方です。
<script setup lang="ts">
type Emits {
(e: "input", value: string): void;
(e: "update:value", value: string): void;
}
defineEmits<Emits>();
const handleInput = ({ target }: { target: HTMLInputElement }) => {
emit("input", target.value);
emit("update:value", target.value);
};
</script>
<template>
<label>
{{ label }}
<input
:value="value"
:type="type"
:placeholder="placeholder"
:disabled="disabled"
@input="handleInput"
/>
</label>
</template>
<script setup>
構文のメリット
- TypeScriptによる型推論のパフォーマンス向上!
- PropとEmitの記述が楽に!TypeScriptで書ける
- templateで使うコンポーネントは、importするだけで使用可能になる!
- 実行パフォーマンスの向上!
参考
Discussion