Vuetifyを使ってToDoアプリをちょっとかっこよくする


この記事でやりたいこと

マテリアルデザインを使って、デザインが苦手なエンジニアがそれなりに見た目の良いアプリを作ること。CSSは自分では一切書きません!!
 今回作るのはToDoアプリですが、Vue.jsでマテリアルデザインを使えるようにするライブラリであるVuetifyをあてる前のものの作り方は以下の記事を参照してください。

  1. 初学者でもVue/Vuexを[確実に]動かせる記事~はじめてのHelloWorld~
  2. Vue.js初学者でも[確実に]ToDoアプリを動かしてVueコンポーネント間データ渡しを学ぶ(本記事)

では前回までの成果物にVuetifyをあてた場合のビフォー/アフターはこちら。

ビフォー↓

アフター↓

上部にアプリバーがつき、入力欄や各種ボタンがオシャレに!!またテーブルのレイアウトが変わり、ページング機能もついています。

Vuetifyを使ってオシャレになろう!!

Vuetifyとは?

Material-UIのコンポーネントを使えるためのライブラリ集合という認識。これでbootstrapのようなグリッドレイアウトやマテリアルデザインに準拠するヘッダーやボタンなどが使用できる。前回までのコードでタスク一覧をを表示するテーブル、インプットフォームの二つを実装してあるのでそれらをかっこよくする。

Vuetifyで使用可能になるMaterial-UIについては公式より拾ってきます。UI-Componentsの欄より拾ってきましょう。

下準備

以下のライブラリをyarn add [ライブラリ名]で追加する。

  "dependencies": {
    "@mdi/font": "^3.6.95",
    "ajv": "^6.10.0",
    "material-design-icons-iconfont": "^4.0.5",
    "vuetify": "^1.5.11",
....
....
....
  }

main.jsに以下の行を追加(グローバルスコープとなることに注意)

main.js
import Vuetify from 'vuetify' // 追加したライブラリを読み込む
import 'vuetify/dist/vuetify.min.css'
import 'material-design-icons-iconfont/dist/material-design-icons.css'
import '@mdi/font/css/materialdesignicons.css'

Vue.use(Vuetify) // Vueライブラリは使用を宣言。グローバルスコープ。

コンポーネントの変更

App.vue
<template>
  <div id="app">
    <v-app> <!-- マテリアルUIはv-appタグで全体を囲むこと!!囲まないと色がおかしくなったりします。
      <AppBar></AppBar> <!-- AppBarコンポーネントをサイトより拾ってくる。
      <InputTask v-on:child-event="TaskAdded"/>
      <taskView v-bind:tasks='tasks' v-on:child-event="TaskFinished"/>
    </v-app>
  </div>
</template>

<script>
import TaskView from './components/TaskView'
import InputTask from './components/InputTask'
import AppBar from './components/AppBar' // AppBarコンポーネントをサイトより拾ってくる。

export default {
  name: 'App',
  components: {
    TaskView,
    InputTask,
    AppBar // コンポーネントを追加
  },

....
TaskView.vue
<template>
  <div class='task'>
    <v-data-table :headers="headers" :items='tasks' class="elevation-1"> <!-- data table を使用。使用方法は公式サイトのテストコードより確認しつつ。
      <template v-slot:items="props">
        <td>{{ props.item.name }}</td>
        <td v-if=props.item.flag class="text-xs-center"><v-btn v-on:click='click(props.item.name)' color='info'> Done </v-btn></td>
        <td v-else class="text-xs-center"><v-btn v-on:click='click(props.item.name)' color='warning'>Not Yet</v-btn></td>
      </template>
    </v-data-table>
  </div>
</template>

<script>
export default {
  name: 'TaskView',
  props: {
    tasks: Array
  },
  data () {
    return {
      headers: [
        {
          text: 'Task Name',
          align: 'left',
          sortable: false,
          value: 'name'
        },
        {
          text: 'Status',
          sortable: false,
          value: 'status'
        }
      ]
    }
  },
  methods: {
    click: function (msg) {
      this.$emit('child-event', msg)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
InputTask.vue
<template>
  <div class='InputTask'>
    <v-layout row wrap>
      <v-flex xs6>
        <v-form ref='form' v-on:submit.prevent='addtask(taskname)'> <!-- form内部を全部マテリアルUIに変更.
          <v-text-field v-model='taskname' placeholder='input the task'></v-text-field> 
          <v-btn v-on:click.prevent='addtask(taskname)' color='success' dark>Submit</v-btn>
        </v-form>
      </v-flex>
    </v-layout>
  </div>
</template>

<script>
export default {
  name: 'InputTask',
  data () {
    return {
      taskname: ''
    }
  },
  methods: {
    addtask: function (msg) {
      this.$emit('child-event', msg)
      this.taskname = ''
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

以上です。CSSを書かないでもGridレイアウトである程度まではなんとかなると思います。特に個人的には入力欄とボタンのマテリアルデザインが好きです。なお、コードはGithubのレポジトリに置いてあります。

終わりに

CSSは勉強することから逃げがち、、、、、おすすめの本とかあったらコメントして教えていただきたいです。よろしくお願いいたします。