Vuetify 3 Alpha の主な変更点

Vuetify は Vue.js で多く使われている UI コンポーネントです。現在のバージョンは Vue 3 には対応していません。

現在 Vue 3 に対応する Alpha 版の Vuetify 3 が公開されています。開発スケジュールは以下のとおりになっています。

リリース目標: 2022年2月 アルファ: 2021年 3月 ベータ: 2021年12月

まだ Alpha 版で安定しないバージョンではありますが Vuetify 3 でどのような機能が追加されるんか見ていきましょう。

インストール

vue-cli

vue-cli 4.0 を利用してプロジェクトを作成します。

vue create my-app

Vue 3 を選択します。

? Please pick a preset: 
  Default ([Vue 2] babel, eslint) 
❯ Default (Vue 3) ([Vue 3] babel, eslint) 
  Manually select features 

Vuetify をプロジェクトに追加します。

cd my-vue-app/
vue add vuetify

Vuetify 3 Preview (Vuetify 3) を選択します。

? Choose a preset: (Use arrow keys)
  Configure (advanced)
  Default (recommended)
  Vite Preview (Vuetify 3 + Vite)
  Prototype (rapid development)
> Vuetify 3 Preview (Vuetify 3)

Vite

Vuetify 3Vite でも使用することでできます。まずは Vite のドキュメントにある手順のとおりにプロジェクトを作成します。

# npm 6.x
npm init vite@latest my-vue-app --template vue

# npm 7+ は追加で 2 つのダッシュが必要:
npm init vite@latest my-vue-app -- --template vue

# yarn
yarn create vite my-vue-app --template vue

# pnpm
pnpm create vite my-vue-app -- --template vue

Vuetify をプロジェクトに追加します。

cd my-vue-app/
vue add vuetify

Vite Preview (Vuetify 3 + Vite) を選択します。

? Choose a preset: (Use arrow keys)
  Configure (advanced)
  Default (recommended)
  Vite Preview (Vuetify 3 + Vite)
  Prototype (rapid development)
> Vuetify 3 Preview (Vuetify 3)

Vuetify の初期化

Vuetify 2 までは new Vuetify() のように Vuetify インスタンスを生成していましたが Vuetify 3 からは Vue 3createApp のように createVuetify をインポートして Vuetify インスタンスを生成します。 (Vue 3 と同じく tree shaking を効かせるためかと思います)

  • Vuetify 2
// src/main.ts
import Vue from 'vue'
import Vuetify from 'vuetify'

const vuetify = new Vuetify({})
Vue.use(vuetify)

new Vue({
  vuetify,
}).$mount('#app')
  • Vuetify 3
// src/main.ts
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createApp } from 'vue'
import App from './App.vue'
import { createVuetify } from 'vuetify'

const vuetify = createVuetify({})

createApp(App)
  .use(vuetify)
  .mount('#app')

デフォルト Prop

Vuetify のインスタンスを生成する際にオプションとしてあるコンポーネントに対してデフォルトの Props を設定できるようになりました。

例えば、以下のようにボタンに対するデフォルトの props を設定できます。

// src/plugins/vuetify.js
import { createVuetify } from "vuetify";

export default createVuetify({
  defaults: {
    VBtn: {
      flat: true,
      disabled: true,
    },
  },
});

以下のように props を指定しないで <v-btn> を配置しても、デフォルト Prop が適用されています。

<template>
  <v-app class="app">
    <div class="flex ma-2">
      <v-btn>Button</v-btn>
    </div>
  </v-app>
</template>

スクリーンショット 2021-12-19 16.03.58

Props は以下の優先度で適用されます。

  1. コンポーネントに直接渡された Props
  2. defaults で設定した Props
  3. Vuetify のデフォルトの Props

Defaults providers

<v-defaults-provider> コンポーネントを利用すると Default providers 配下のコンポーネントにのみ上書きして defaults の設定を適用できます。

<template>
  <v-app class="app">
    <div class="flex ma-2">
      <v-btn>Button</v-btn>
      <v-defaults-provider :defaults="defaults">
        <v-btn>Button inside providers </v-btn>
      </v-defaults-provider>
    </div>
  </v-app>
</template>

<script setup>
const defaults = {
  VBtn: {
    color: "secondary",
    disabled: false,
  },
};
</script>

スクリーンショット 2021-12-19 16.14.53

テーマ

カスタムテーマ

Vuetify の提供する ligthdark のテーマに加えてカスタムのテーマを設定できるようになりました。(それに伴い theme の isDark プロパティは削除されました)

使用するテーマは defaultTheme プロパティで設定できます。

// src/plugins/vuetify.ts
import { createVuetify, ThemeDefinition } from "vuetify";

const myCustomTheme: ThemeDefinition = {
  dark: false,
  colors: {
    background: '#FFFFFF',
    surface: '#FFFFFF',
    primary: '#FF7043',
    error: '#B00020',
    info: '#2196F3',
    success: '#4CAF50',
    warning: '#FB8C00',
  }
}

export default createVuetify({
  theme: {
    defaultTheme: 'myCustomTheme',
    themes: {
      myCustomTheme
    }
  }
});

テーマの変更

ユーザーが動的にアプリケーションのテーマを切り替えることができるようにするためには <v-app>theme props を渡すことで切り替えることができます。

<template>
  <v-app :theme="theme">
    <v-container class="px-0" fluid>
      <v-radio-group v-model="theme">
        <v-radio color="primary" label="Light Theme" value="light" />
        <v-radio color="primary" label="Dark Theme" value="dark" />
        <v-radio color="primary" label="My Custom Theme" value="myCustomTheme" />
      </v-radio-group>
    </v-container>
  </v-app>
</template>

<script setup>
import { ref } from "vue";

const theme = ref("light");
</script>

vuetyfy-change-theme

Theme providres

<v-theme-provider> コンポーネントは配下のコンポーネントのみにテーマを適用できます。

デフォルトでは <v-theme-provider> 内では背景色は元のテーマのままとなります。背景色にもテーマを適用させるには、with-background props を渡します。

<template>
  <v-app>
    <v-theme-provider theme="dark">
      <div class="pa-10">
        <v-card title="Title" subtitle="Subtitle"></v-card>
      </div>
    </v-theme-provider>
    <v-theme-provider theme="light">
      <div class="pa-10">
        <v-card title="Title" subtitle="Subtitle"></v-card>
      </div>
    </v-theme-provider>
    <v-theme-provider theme="dark" with-background>
      <div class="pa-10">
        <v-card title="Title" subtitle="Subtitle"></v-card>
      </div>
    </v-theme-provider>
  </v-app>
</template>

スクリーンショット 2021-12-19 16.59.50

コンポーネント単位のテーマ

Vuetify 2 ではコンポーネント単位でダークテーマを適用させたい場合には dark props を渡して設定していました。

  • Vuetify 2
<template>
  <v-app>
    <v-container>
      <v-card dark>
        <v-card-title>card title</v-card-title>
      </v-card>
    </v-container>
  </v-app>
</template>

Vuetify 3 では前述のとおり lightdark 以外のテーマも設定できるので代わりに theme props で設定します。

<template>
  <v-app>
    <v-container>
      <v-card theme="dark">
        <v-card-title>card title</v-card-title>
      </v-card>
    </v-container>
  </v-app>
</template>

スクリーンショット 2021-12-19 18.51.01

ブレークポイント

Vuetify 2 では JavaScript から現在のブレークポイントにアクセスするために this.$vuetify.breakpoints からアクセスできました。例えば現在の画面サイズが sm 以下の場合にのみ実行したい場合には以下のようにします。

  • Vuetify 2
<template>
  <v-app>
    <h1>{{screenName}}</h1>
  </v-app>
</template>

export default {
  computed: {
    screenName() {
      if (this.$vuetify.breakpoints.smAndDown) {
        return 'mobile'
      } else {
        return 'desktop'
      }
    }
  }
}

Vuetify 3 では useDisplay() 関数により現在のブレークポイントを取得できます。useDisplay() の返り値は ref でラップされているのでリアクティブ変数です。

  • Vuetify 3
<template>
  <v-app>
    <h1>{{ screenName }}</h1>
  </v-app>
</template>

<script setup>
import { computed } from "vue";
import { useDisplay } from "vuetify";
const display = useDisplay();

const screenName = computed(() => {
  if (display.smAndDown.value) {
    return "mobile";
  } else {
    return "desktop";
  }
});
</script>

プラットフォーム

useDisplay() から新たにユーザーエージェントの情報を取得できるようになりました。

  platform: {
    android: boolean
    ios: boolean
    cordova: boolean
    electron: boolean
    chrome: boolean
    edge: boolean
    firefox: boolean
    opera: boolean
    win: boolean
    mac: boolean
    linux: boolean
    touch: boolean
    ssr: boolean
  }
<script setup>
import { useDisplay } from "vuetify";
const display = useDisplay()

if (display.platform.value.chrome) {
 console.log('I am chrome')
} else if (display.platform.value.firefox) {
 console.log('I am firefox')
} else if (display.platform.value.edge) {
 console.log('I am edge')
}
</script>

カード

新しいコンポーネントがいっぱい増えています。が、詳細は不明です。

  • v-card-avatar
  • v-card-header
  • v-card-header-text
  • v-card-img
  • v-card-media

イメージ

<v-img>contain props は削除されデフォルトで contain が挙動となるようになりました。Vuetify 2 までの挙動を維持するために新たに cover props が追加されました。

つまり、以下の 2 つのコードは同等のものとなります。

  • Vuetify 2
<template>
  <v-img src="/images/sample.png" contain />
</template>
  • Vuetify 3
<template>
  <v-img src="/images/sample.png" />
</template>

Vuetify 2 では画像の表示するため <div> タグに background-image を指定していましたが Vuetify 3 からは <img> タグを使用するようになりました。

ボタン

サイズ

以下のサイズを決定する props は削除され、代わりに size プロパティで指定するようになりました。

  • x-small

  • small

  • large

  • x-large

  • Vuetify 2

<template>
  <v-app class="app">
    <div class="flex flex-colmun">
      <v-btn color="primary" class="mx-2" x-small>Extra Small Button</v-btn>
      <v-btn color="primary" class="mx-2" small>Small Button</v-btn>
      <v-btn color="primary" class="mx-2">Default Button</v-btn>
      <v-btn color="primary" class="mx-2" large>Large Button</v-btn>
      <v-btn color="primary" class="mx-2" x-large>Extra Large Button</v-btn>
    </div>
  </v-app>
</template>
  • Vuetify 3
<template>
  <v-app class="app">
    <div class="flex flex-colmun">
      <v-btn color="primary" class="mx-2" size="x-small">Extra Small Button</v-btn>
      <v-btn color="primary" class="mx-2" size="small">Small Button</v-btn>
      <v-btn color="primary" class="mx-2" size="default">Default Button</v-btn>
      <v-btn color="primary" class="mx-2" size="large">Large Button</v-btn>
      <v-btn color="primary" class="mx-2" size="x-large"
        >Extra Large Button</v-btn
      >
    </div>
  </v-app>
</template>

スクリーンショット 2021-12-19 16.05.13

variant

以下の props は廃止され代わりに variant で指定するようになりました。

  • text
  • outlined
  • plain

variant には以下を設定できます。

  • 'contained'

  • 'outlined'

  • 'plain'

  • 'text'

  • 'contained-text'

  • Vuetify 2

<template>
  <v-app>
    <v-container>
      <v-btn color="primary" text>text button</v-btn>
      <v-btn color="primary" outlined>outlined button</v-btn>
      <v-btn color="primary" plain>outlined button</v-btn>
    </v-container>
  </v-app>
</template>
  • Vuetify 3
<template>
  <v-app>
    <v-container>
      <v-btn color="primary" variant="outlined">outlined button</v-btn>
      <v-btn color="primary" variant="text">text button</v-btn>
      <v-btn color="primary" variant="plain">plain button</v-btn>
      <v-btn color="primary" variant="contained">contained button</v-btn>
      <v-btn color="primary" variant="contained-text">contained-text button</v-btn>
    </v-container>
  </v-app>
</template>

スクリーンショット 2021-12-19 17.55.23

depressed は廃止され代わりに flat となりました。 stacked プロパティが追加されました。(詳細は不明)

<template>
  <v-app>
    <v-container>
      <v-btn color="primary" stacked>stacked button</v-btn>
      <v-btn color="primary" flat>flat button</v-btn>
    </v-container>
  </v-app>
</template>

スクリーンショット 2021-12-19 17.57.22

No SSR

<v-no-ssr> コンポーネント配下はサーバーサイドでは実行されなくなります。

共通 Props?

いろんなコンポーネントに position props を渡せるようになったようです。

  • interface
export interface PositionProps {
  absolute?: boolean
  bottom?: boolean | number | string
  fixed?: boolean
  left?: boolean | number | string
  position?: Position
  right?: boolean | number | string
  top?: boolean | number | string
}
<template>
  <v-app>
    <v-container>
      <v-btn absolute top="100">button</v-btn>
      <v-card
        absolute
        top="0"
        left="200"
        title="title"
        subtitle="subtitle"
      ></v-card>
    </v-container>
  </v-app>
</template>

スクリーンショット 2021-12-19 18.41.58

position 以外にも以下の props はコンポーネントの共通の props と定義されているっぽい?

  • density
  • height
  • maxHeight
  • maxWidth
  • minHeight
  • minWidth
  • width
  • theme
  • tag
  • elevation
  • border
  • rounded

v-intersect

v-intersect ディレクティブの引数の順番が変わり isIntersecting が初めの引数になりました。

v-kbd

kbdをラップしたコンポーネント?

  <template>
  <v-app>
    <v-container>
      <v-kbd>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, magnam
        repudiandae. Porro dolorum quo nesciunt laboriosam minus voluptate,
        reiciendis quibusdam necessitatibus debitis rerum cum inventore.
        Necessitatibus nostrum quo minima quia?
      </v-kbd>
    </v-container>
  </v-app>
</template>

スクリーンショット 2021-12-19 19.13.08

Contributors

> GitHub で修正を提案する
この記事をシェアする
Twitterで共有
Hatena

関連記事