前回記事でvueとexpressでフロントエンドとバックエンドを繋ぐことができるようになった。
次はフロントエンド側を綺麗に見せるためにvuetifyというUIフレームワークをいれてみる。
vuetifyをインストール
※ 実行すると、App.vueやmain.ts、package.jsonなど複数のファイルがvuetifyのデフォルトに上書きされる。実行前にどっかに退避させておくのが大事。
package.json
を含むディレクトリ($vue create front
でプロジェクトfrontを作成していればfront下にある)で以下のコマンド実行。
$ vue add vuetify
📦 Installing vue-cli-plugin-vuetify...
+ vue-cli-plugin-vuetify@2.0.5
added 4 packages from 4 contributors and audited 40952 packages in 8.254s
found 25 vulnerabilities (20 low, 5 moderate)
run `npm audit fix` to fix them, or `npm audit` for details
✔ Successfully installed plugin: vue-cli-plugin-vuetify
? Choose a preset: Default (recommended)
🚀 Invoking generator for vue-cli-plugin-vuetify...
📦 Installing additional dependencies...
added 2 packages from 1 contributor and audited 40959 packages in 11.674s
found 25 vulnerabilities (20 low, 5 moderate)
run `npm audit fix` to fix them, or `npm audit` for details
⚓ Running completion hooks...
✔ Successfully invoked generator for plugin: vue-cli-plugin-vuetify
The following files have been updated / added:
src/assets/logo.svg
src/plugins/vuetify.ts
vue.config.js
package-lock.json
package.json
public/index.html
src/App.vue
src/components/HelloWorld.vue
src/main.ts
You should review these changes with git diff and commit them.
vuetify Discord community: https://community.vuetifyjs.com
vuetify Github: https://github.com/vuetifyjs/vuetify
vuetify Support Vuetify: https://github.com/sponsors/johnleider
$ npm run serve
新しくなったvuetifyのページが現れる。App.vueは消え去っている。。
まずは、エラーを消す作業から。
参考としたのはこの2つ
- https://dev.classmethod.jp/client-side/spa/getting-started-class-style-vuetify/
- https://github.com/vuetifyjs/vuetify/issues/8289
2020年3月現在ではtsconfig.json
の修正のみでエラーはなくなった。
"types": [
"webpack-env",
"mocha",
"chai",
"vuetify" //これを追記。
]
その後失われたApp.vueを元に戻す。
なお、無事インストールできたのにこんな感じのエラーが出てフロントエンドが立ち上がらない場合はサーバーを再起動してもう一回npm run serve
すると治る。
throw er; // Unhandled 'error' event
参考) https://qiita.com/M-ISO/items/d693ac892549fc95c14c
基本的な使い方
App.vueなどを参考にするとわかるが、vuetifyでは必ず<v-app></v-app>
で囲われた中で各種タグを使う必要がある。
<template>
<v-app>
ここでv-〇〇達を使ってあげる。
</v-app>
</template>
v-slot
vuetifyを見ているとv-slot
を使うものがいくつか見つかる。
正直使わないから飛ばしててまともに知らなかったので勉強。
これまでコンポーネントの親子の関係では親から子に変数やjsonなどの値をプロパティとして渡し、値をどう表示するかは子コンポーネント側で指定していた。ボタンに表示する文言を親から受け取るけれど、どこに配置するかなどは子側で決めるといった具合だろうか。
slotは、子コンポーネントの中身を直接ハードコードせず、親側で動的に決められるようにした仕組み。これにより、vuetifyなどのUIフレームワークに対して柔軟に値をわたし、表現することができるようになっている。
スロットでは、子コンポーネントの中で<slot></slot>
とした部分に対し、親側から指定されたテンプレートがまるごとはめ込まれる。
slotタグの間にはデフォルトの表示を指定しておくこともできる。
名前付きスロット
また、以下のように複数のスロットを名前で区別することもできる。(以下公式リファレンスの例)
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p> *
<p>And another one.</p> *
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
- 子コンポーネントで名前を指定しないもの(main)はdefaultという名前が暗黙裡につけられる。
- 親側で名前を指定しない箇所(*)はdefaultに入る。
<template v-slot:default>
とすることも可能。
スコープ付きスロット
子のプロパティに対してslotで流し込むテンプレートの中からアクセスしようとするとundefinedとなってしまい、アクセスできない。
これを回避するためにスロットに対してスコープを当てる。
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
//もしくは省略形
<current-user>
<template v-slot:default="{ user }">
{{ user.firstName }}
</template>
</current-user>
//もっと省略形
<current-user>
<template #default="{ user }">
{{ user.firstName }}
</template>
</current-user>
上記は親が子のプロパティをslotPropsとして受け取り、そのなかから必要なuserの中のfirstNameにアクセスして表示するという流れ。slotPropsは特になんでもいいしなんなら省略形で書くことで省ける。
一例 v-menu
実際にv-slot
が使われる1つの例としてv-menu
がある。
以下の例ではアイコンv-icon
を格納したボタンv-btn
をスロットに渡している。クリック時にコンポーネントが有効になる。
<v-menu
left
bottom
>
<template v-slot:activator="{ on }">
<v-btn icon v-on="on">
<v-icon small>mdi-arrow-down-drop-circle</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="n in 5"
:key="n"
@click="() => {}"
>
<v-list-item-title>Option {{ n }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
v-menu
はdefaultとactivatorの2種類のスロットを持ち、ここで登場しているactivatorは以下のプロパティを持っている。
{
on: { [eventName]: eventHandler }
value: boolean
}
このonを受け取り変数onに格納するのがv-slot:activator="{ on }"
。
ここで受けるonは複数のイベントハンドラを一括で指定できるオブジェクト構文という形で指定している。
詳しくは以下参照
参考)https://qiita.com/aotoriii/items/06ae49c135061a12b75e
トラブルシュート
<v-icon>
で括った文字列がそのまま表示されてしまう場合
おそらくこれで対応可能(vuetifyのversion2.x云々の問題?)
https://qiita.com/tamonmon/items/5656614462241cd00255
以下のパッケージを入れる。
front$ npm install @mdi/js file-loader material-design-icons-iconfont --save-dev
以下ファイルに追記。
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
import 'material-design-icons-iconfont/dist/material-design-icons.css';
Vue.use(Vuetify);
export default new Vuetify({
});
上記対応後再度実行すると正常にアイコンが表示される。
98% after emitting CopyPlugin
で止まってしまったら一度サーバを再起動してもう一回実行するとうまくいく。