2022年4月現在 Vue3 + Vuetify3(Beta)でどこまでできるか
昨年、Zenn に Vue を使ったアプリの作り方について投稿しました。
上記投稿時点で Vue3 を使うことはできましたが、使おうと思っていた UIフレームワークの Vuetify が Vue3 に対応していなかったので、Vue2 を使っていました。
あれから半年以上たって、Vue3 対応の Vuetify3 がアルファからベータ版になり、
公式サイトを見るといろいろできそうな感じに見えたので、試しに Vue3 + Vuetify3 で Webアプリを作ってみました。
目標
先日、オープンデータカタログサイトリストの Web API を以下のサイトに公開しました。
ここで公開したデータの検索サイトを作ろうと思います。
一応目標として、このサイト(React + Material-UIで作成)のような見た目を目指すことにしました。
出来たもの
こんな感じにしあがりました。
Vuetify3 についていくつか思ったように動かない部分がありましたが、目標に近い形で作れたと思います。
作成にあたって以下を利用しています。
- Vite
- Vue3
- Vuetify3(Beta 0)
- Vue Router4
- Tailwind CSS
以下では、Vuetify3 を利用している部分を中心に紹介します。
ナビゲーションバー
v-app-bar
をそのまま使いました。問題なく動きました。
<v-app-bar class="select-none">
<v-app-bar-title>
<span class="cursor-pointer" @click="router.push('/')">オープンデータカタログ検索</span>
</v-app-bar-title>
<v-btn icon @click="dialog = true">
<v-icon>mdi-information-outline</v-icon>
</v-btn>
</v-app-bar>
フッター
v-footer
を使います。問題なしです。
<v-footer>
<v-card elevation="0" rounded="0" class="text-center w-full">
<v-card-text>
<a href="https://uedayou.net/" target="_blank" rel="noopener noreferrer" class="no-underline"> @uedayou </a>
{{ ' ' + new Date().getFullYear() }}. Some rights reserved.
</v-card-text>
</v-card>
</v-footer>
検索フィールド
v-text-field
を使いました。フィールド内側のアイコンは append-inner-icon
外側は append-icon
として定義できるようです。
押したときの挙動は、@click:append-inner
、@click:append
に指定できます。
<v-text-field
label="検索"
placeholder="検索したい語を入力してください"
variant="outlined"
hide-details="true"
:append-inner-icon="query.length > 0 ? 'mdi-close' : ''"
append-icon="mdi-magnify"
v-model="query"
@click:append-inner="query = '', reset()"
@click:append="search(query)"
@keyup.enter="search(query)"
></v-text-field>
アイコンのカーソルをポインターにしたかったので、以下も追加しています。
<style lang="scss">
.v-field,
.v-input {
&__append {
&,
&-inner {
@apply cursor-pointer;
}
}
}
</style>
ページネーション
v-pagination
でシンプルに実現できます。
<v-pagination v-model="page" :length="Math.ceil(results.length / itemsPerPage)"></v-pagination>
テーブル
v-table
を使います。
アプリ内では各オープンデータカタログサイトの詳細を表示する部分で使っています。
<v-table v-if="site">
<tbody>
<tr>
<td>名称</td>
<td>{{ title }}</td>
</tr>
<tr>
<td>URL</td>
<td>
<a :href="site.url" target="_blank" rel="noopener noreferrer">{{ site.url }}</a>
</td>
</tr>
...
</tbody>
</v-table>
タグ表示
v-chip
をタグ表示に使いました。
<v-chip v-for="term in site.terms" color="blue" variant="outlined">
{{ term }}
</v-chip>
検索結果表示
v-card
を使って検索結果を表示しています。幅等のスタイルを Tailwind CSS で調整しています。
<v-card
v-for="item in results.slice((page - 1) * itemsPerPage || 0, page * itemsPerPage)"
:key="item.id"
class="p-4 grid items-center text-center select-none"
>
<div v-if="top" @click="router.push(`/${item.type}`)" class="text-sm text-gray-500 cursor-pointer">
{{ getTypename(item.type) }}
</div>
...
</v-card>
カテゴリの表示
v-expansion-panels
で検索カテゴリが不要な場合、隠すようにしています。
<v-expansion-panels class="md:mx-4 my-4" v-model="panel">
<v-expansion-panel>
<v-expansion-panel-title class="select-none"> 提供団体 </v-expansion-panel-title>
<v-expansion-panel-text>
<div class="grid sm:grid-cols-4 gap-4 items-stretch">
<v-card v-for="type in types" @click="router.push(`/${type.id}`)" class="p-4 text-center cursor-pointer">
{{ type.name }}
</v-card>
</div>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
アプリの詳細表示
アプリの詳細を v-dialog
を使って表示するようにしました。ナビゲーションバーの (i)
ボタンを押すことで表示できます。
デフォルトのまま使うとサイズや表示位置がおかしくなってしまったので<style>
タグ内でオーバーライド、本文がはみ出る場合にスクロールさせるため :class="{ 'overflow-y-auto': dialog }"
を指定しました。
動いていますがこれが正しい方法かどうかは疑問です。
<v-row justify="center">
<v-dialog v-model="dialog">
<v-card class="rounded-lg" :class="{ 'overflow-y-auto': dialog }">
<v-card-title>
<span class="text-h5">オープンデータカタログ検索について</span>
</v-card-title>
<v-card-text class="grid gap-x-2 gap-y-4">
<p>ここでは、日本国内で公開されるオープンデータカタログサイトを検索することができます。</p>
...
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="dialog = false"> 閉じる </v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-row>
<style lang="scss">
.v-dialog {
.v-overlay {
&__content {
max-height: calc(100% - 48px) !important;
max-width: calc(100% - 2rem) !important;
@apply flex flex-col m-4;
}
}
}
</style>
おわりに
Vue3 と まだ初期ベータ(2022年4月現在)の Vuetify3 を使って Webアプリを作ってみました。
Vuetify3 は今でも一部を除き問題なく動くものが多いような感じでした。
用途によっては現時点でも Vuetify3 を使ってもいいかもしれません。
また、コード部を Vue 3.2 から使える script setup
構文で書きましたが、慣れが必要な部分もありますが他の言語よりも圧倒的に少ないコード量で Webアプリを作ることができました。
コンポーネントが import
で直接使えたりとさっと作りたい場合は魅力的な機能だと思います。
<script setup lang="ts">
import PrefPanel from './PrefPanel.vue'
import TypePanel from './TypePanel.vue'
</script>
<template>
<TypePanel />
<PrefPanel />
...
</template>
script setup
構文について以下のページを参考にさせていただきました。
ここで作成した Webアプリのソースコードを GitHub で公開しています。
あくまでも Vuetify3 の初期ベータの実装であることを留意してください。
データセット(JSON)を変更してある程度手直しすれば、他のデータの検索アプリとしても流用できそうに思います。
そういったニーズがあれば、活用してみてください。
Discussion