ブログ
これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。
Vue3のSFC(single file component)で<script setup>を使って楽をする
Okuda
3 years
<script setup> は単一ファイルコンポーネント(SFC)内で Composition API を使用するコンパイル時のシンタックスシュガー。
<script> の代わりに <script setup> を使用することで setup() 関数の内容としてコンパイルされるので setup() を省略できる。
setup内でreturnしなくてもトップレベルのものは<template>内で使用できる。
今までとは<template>と<script>の順序が入れ替わり、
<template>、<script>、<style>の順になる
これはコーディングルール的なもの。
コンポーネントにはパスカルケースを推奨。
メリットとしては
- お決まりのパターンを減らし簡潔に書ける
propsとemitの定義にTypeScriptの構文が使える- ランタイムのパフォーマンスが向上
- IDE のパフォーマンスが向上
vscodeの拡張機能は「Vetur」から「Volar」に変更する
トップレベルのバインディング(変数、関数、インポート)
<script setup> 内で宣言されたトップレベルのバインディング(変数、関数、インポート)は、テンプレートで直接使用できる。
<script setup> 内でインポートされたカスタムコンポネントはタグ名として直接使用できる。
<script setup>
// 変数
const msg = 'Hello!'
// 関数 関数を宣言するだけでテンプレート内で使用可能
function log() {
console.log(msg)
}
//インポート `capitalize` はテンプレート内で使用可能
import { capitalize } from './helpers'
// カスタムコンポネント
import MyComponent from './MyComponent.vue'
</>
<template>
<!-- 変数と関数 -->
<div @click="log">{{ msg }}</div>
<!-- インポートした関数 -->
<div>{{ capitalize('hello') }}</div>
<!-- インポートしたカスタムコンポネント -->
<MyComponent />
</template>
リアクティビティ
ref、reactive、computedなどはそのまま
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">{{ count }}</button>
</template>
コンポーネント
<script setup>内で動的コンポーネントを使う場合は、コロンをつけた:is バインディングを使う必要がある。
SFCはファイル名で暗黙的に参照するので、FooBar.vue というファイル名は、テンプレート内で
名前と競合する名前付きインポートがある場合、インポートでエイリアスを作成する。
<script setup>
// 動的にコンポネントを使用する
import Foo from './Foo.vue'
import Bar from './Bar.vue'
// 変数
const someCondition = true
// 暗黙的名前空間付きコンポーネント
// import Bar from './Bar.vue'
import { Baz as Baz2 } from './your/Baz.vue'
</script>
<template>
<component :is="Foo" />
<component :is="someCondition ? Foo : Bar" />
<!-- Baz.vue -->
<Baz />
<Baz2 />
</template>
名前付きコンポネント (ネスティッド コンポネント)
<form.Bar> のようにドット付きのコンポーネントタグを使って、オブジェクトプロパティの下にネストしたコンポーネントを参照することができる。
components/Forms/Input.vue
Formsにネストされるコンポネント
<template>
<input type="text" />
</template>
components/Forms/Checkbox.vue
Formsにネストされるコンポネント
<template>
<input type="text" />
</template>
components/Forms.js
このファイルでまとめる
export { default as Input } from "./components/Forms/Input.vue";
export { default as Checkbox } from "./components/Forms/Checkbox.vue";
App.vue
使用するとき
<script lang="ts" setup>
import * as Form from "./components/Forms";
</script>
<template>
<Form.Input />
<Form.Checkbox />
</template>
props と emits
<script setup> の中で props と emits を宣言するには defineProps と defineEmits を使用する。
インポートする必要なし。
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['change', 'delete'])
</script>
useSlots と useAttrs
useSlots() と useAttrs() を使用。
<script setup>
import { useSlots, useAttrs } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
</script>
defineExpose
<script setup> コンポーネントのプロパティを明示的にテンプレート内に公開する場合は defineExpose を使用する。
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
トップレベルの await
<Suspense>で待機対象となるので必ず<Suspense>と組み合わせて使用しなくてはならない。
<script setup>
const {data, status} = await axios.get(`http://api.comc`)
</script>
<template>
<suspense>
<template #default>{{data}}</template>
<template #fallback>Loading...</template>
</suspense>
</template>
純粋にawaitしたい場合は、以下のような方法がある。
<script setup>
import { onBeforeMount } from "vue";
onBeforeMount(async () => {
const { status, data } = await axios.get(`http://api.comc`)
});
コメントはありません。