ひびのログ

日々ではないけどログを出力していくブログ

script setup の書き方

せっかく作ったので供養。

書き方

前提

Vue.js 3.4 以上

コード

<script setup lang="ts" generic="T">
import { ref } from 'vue'
// 子コンポーネント読み込み
import ChildComponent from 'ChildComponent'

// options
defineOptions({
  inheritAttrs: false
})

// --------------------------------

// v-model は defineModel を使う
// required: true を指定する
const visible = defineModel({ required: true })
// 必須でない場合は基本的に default 値を設定する
const name = defineModel({ default: '' })
// defineModel が複数存在する場合は、メインとなる一つ以外に名前をつける
const email = defineModel('email', { default: '' })

// --------------------------------

// props は型引数で定義(type-based declaration)
// 定義を分ける必要はない
const props = defineProps<{
  foo: T
  bar?: string[]
}>()

// デフォルト値を指定する場合の書き方
// 必須ではない props がある場合は必須、ないなら指定してはいけない
const props = withDefaults(defineProps<Props>(), {
  baz: () => ['one', 'two']
})

// --------------------------------

// emit も props と同様に型引数で定義
// 引数は名前付きタプルで指定する
const emit = defineEmits<{
  change: [id: number]
  update: [value: string]
}>()

// --------------------------------

// slot
const slots = defineSlots<{
  default(props: { message: string }): any
}>()

// --------------------------------

// 動的なスタイル
// クラスの付け替えではなく、CSS から変数を参照する
const color = computed(() => value.value === 'red' ? 'red' : 'black')

// --------------------------------

const value = ref('')
const method = () => {}
</script>

<template>
  <ChildComponent>
    <section class="parent_section">
      <slot :msg="value" />
    </section>
  </ChildComponent>
</template>

<style lang="scss" scoped>
.parent_section {
  border: solid 1px #000;
  color: v-bind(color);
}
</style>

  • top level await は使用しない
    • suspense がまだ実験的機能
  • script setup と通常の script は併用禁止
    • defineOptions を使う
  • 基本的にスタイルガイドに合わせる

検討したこと

  • ブロックの順番
    • 明示的に「この順番がいい」ということは書いていない
    • Vue.js 公式では基本的に script, template, style の順番で記述されており、こちらがデファクトスタンダードと思われる
    • デファクトスタンダードに合わせない積極的な理由はないと思うので、それに合わせるのが良さそう
    • React も Svelte も script 先行だし、それに合わせたほうが認知負荷が下がる=Vue の経験が浅くても読みやすくなる
  • CSS の v-bind()
    • BEM でいう Modifier が撲滅できるし、JS の仕組みに沿った管理ができる(Composable 化とか)ので、積極的に使っていくのが良さそう

参考