はじめに
この記事では@vue/cliとVuetifyを使って初めてWeb開発する人向けに、よく使う構文やコンポーネントをまとめました。基本的にコピペで使えるように、単一ファイルコンポーネントを使用しています。
動作環境
- Vue.js: 2.6
- @vue/cli: v.4.4.6
- node: v8.10.0
- npm: v5.6.0
導入
Vue.cilのインストールとプロジェクトの作成
以下の記事を参考にして@Vue.cil をインストールし、プロジェクトを作成してください (ここでは “my-app”という名前で作成しました)。
なお、プロジェクトを作成する際は「Manually select features」を選択し、「Router」にチェックを付けておいてください。それ以外の質問は全てYesかEnterでいいです。
Vuetifyのインストール
BashやVsCodeのターミナルなどで、先ほど作成したプロジェクト(ここでは”my-app”)に移動し、Vuetifyを導入してください。途中の質問は全てYes(or Enter)でいいです。
1 2 3 4 5 |
# my-appフォルダへ移動 cd my-app # Vuetifyの導入 vue add vuetify |
Vue Serverの起動
以下のコマンドを実行してhttp://localhost:8080/へアクセスしてください。
1 |
npm run serve |
サーバーが起動しない場合
クローンしてきたプロジェクトだと以下のようなエラーが出る場合があります。
1 2 3 4 5 6 7 8 9 10 |
npm ERR! code ELIFECYCLE npm ERR! errno 126 npm ERR! mywebapp@0.1.0 serve: vue-cli-service serve npm ERR! Exit status 126 npm ERR! npm ERR! Failed at the mywebapp@0.1.0 serve script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! /var/root/.npm/_logs/2018-09-25T07_17_36_807Z-debug.log |
(引用元:https://github.com/vuejs/vue-cli/issues/2596)
これはモジュールがインストールされていないことによるエラーであることがほとんどなので、以下のコマンドを実行してモジュールをインストールしてください。
1 |
npm install |
以下の画面が表示されたらVueの導入は完了です。
Appファイルの編集
src/App.vueファイルのコードを全て削除し、以下のコードをコピペしてください。
Vuetifyのコンポーネントは<v-app></v-app>タグ内で呼ぶ必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<template> <!-- App.vue --> <v-app> <v-navigation-drawer app> <!-- --> </v-navigation-drawer> <v-app-bar app> <!-- --> </v-app-bar> <!-- Sizes your content based upon application components --> <v-main> <!-- Provides the application the proper gutter --> <v-container fluid> <!-- If using vue-router --> <router-view></router-view> </v-container> </v-main> <v-footer app> <!-- --> </v-footer> </v-app> </template> <script> export default { name: "App", components: {}, data: () => ({}), methods: {}, }; </script> <style scoped></style> |
(引用:https://vuetifyjs.com/en/components/application/)
また、 src/views/Home.vueの中身を削除し、以下をコピペしてください。
1 2 3 4 5 |
<template> <div class="home"> <h1>This is Home view</h1> </div> </template> |
以下の画面になれば準備完了です。
Routerについてはまた後で説明しますが、この画面はApp.vueの<router-view></router-view>タグによって、/home のURLパスに割り当てられたHome.vueの画面が表示されています。
以降、Home.vueを編集していきます。
Vuetify チートシート
パスの指定方法
vueファイル内でコンポーネント等をimportする際、パスを指定する必要があります。その際、’../../view/Example’のように相対パスで指定してもいいのですが、’@’を使うとsrcフォルダを絶対パスで指定できます。以下例です。
1 2 3 |
"@/" ← src/ "@/assets/logo.png" "@/views/Home" |
Vuetifyのカラー設定
@/plugins/vuetify.js のexport defaultメソッド内に以下の内容を追加してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import Vue from "vue"; import Vuetify from "vuetify/lib"; import colors from "vuetify/lib/util/colors"; Vue.use(Vuetify); export default new Vuetify({ theme: { themes: { light: { primary: colors.red.darken1, // #E53935 secondary: colors.red.lighten4, // #FFCDD2 accent: colors.indigo.base, // #3F51B5 myColor: colors.green.accent4, myColor2: colors.blue.lighten1, }, }, }, }); |
(引用:https://vuetifyjs.com/ja/styles/colors/)
@/views/VuetifyColor.vueに以下をコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<template> <div class="vuetifyColor"> <h1>This is VuetifyColor view</h1> <v-container class="d-flex flex-column"> <v-btn class="accent">accent</v-btn> <v-btn class="myColor">myColor</v-btn> <v-btn :style="{ 'background-color': this.$vuetify.theme.themes.light.myColor2, }" >変数として使う場合</v-btn > <v-btn :color="myColor">算出プロパティを使う場合</v-btn> </v-container> </div> </template> <script> export default { computed: { myColor: function () { return this.$vuetify.theme.themes.light.myColor2; }, }, }; </script> |
classのバインディング方法
@/views/ClassBind.vueを作成し、以下をコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<template> <div class="classBind"> <h1>This is AddClass view</h1> <v-container class="d-flex flex-column"> <v-btn>クラス無し</v-btn> <v-btn class="info">基本形</v-btn> <v-btn :class="onBlue">クラスオブジェクト使用</v-btn> <v-btn :class="{ info: !classOn }">クラスOFF</v-btn> <v-btn :class="{ info: classOn }">クラスON</v-btn> <v-btn :class="classMethod">メソッド</v-btn> <v-btn :class="['warning--text', { success: classOn }]">複合形</v-btn> </v-container> </div> </template> <script> export default { name: "ClassBind", data: () => ({ classOn: true, onBlue: { info: true, }, }), computed: { classMethod: function() { return { info: true, }; }, }, }; </script> |
また、@/views/Home.vueを以下に書き換えて、AddClass.vueをimportしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<template> <div class="home"> <h1>This is Home view</h1> <ClassBind></ClassBind> </div> </template> <script> import ClassBind from "@/views/ClassBind"; export default { components: { ClassBind, }, }; </script> |
以下の画面が表示されます。
以下、説明に使用するコンポーネントのコードのみを掲載しますが、同様にHome.vue等にコンポーネントを importして使ってください。
styleのバインディング方法
@/views/StyleBind.vueを作成し、以下をコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<template> <div class="styleBind"> <h1>This is StyleBind view</h1> <v-container class="d-flex flex-column"> <v-btn>スタイル無し</v-btn> <v-btn style="color: red">基本形</v-btn> <v-btn :style="onRed">スタイルオブジェクト使用</v-btn> <v-btn :style="styleMethod">メソッド</v-btn> <v-btn :style="{ color: 'red', fontSize: '2rem' }">複数形</v-btn> <v-btn :style="[onRed, largeFont]">配列形</v-btn> <v-btn :style="[onRed, { fontSize: '2rem' }]">複合形</v-btn> </v-container> </div> </template> <script> export default { name: "StyleBind", data: () => ({ styleOn: true, onRed: { color: "red", }, largeFont: { fontSize: "2rem", }, }), computed: { styleMethod: function() { return { color: "red", }; }, }, }; </script> |
子コンポーネントのCheckboxの使い方
@/views/ParentCheckbox.vueを作成し、以下をコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<template> <div class="parentCheckbox"> <ChildCheckbox :parentSelected="selected" :parentData="data" @update-data="update" ></ChildCheckbox> {{ selected }} </div> </template> <script> import ChildCheckbox from "@/components/ChildCheckbox"; export default { name: "ParentCheckbox", data: () => ({ selected: [], data: [ { id: 0, name: "dog" }, { id: 1, name: "cat" }, { id: 2, name: "cow" }, ], }), components: { ChildCheckbox, }, methods: { update: function (newVal) { this.selected = newVal; }, }, }; </script> |
@/components/ChildCheckbox.vueを作成し、以下をコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<template> <div class="childCheckbox"> <v-container> <template v-for="(item, index) in parentData"> <v-checkbox v-model="selected" :label="item.name" :value="item.id" :key="`childCheckbox-${index}`" ></v-checkbox> </template> </v-container> </div> </template> <script> export default { name: "ChildCheckbox", props: { parentSelected: { type: Array, default: function () { return []; }, }, parentData: { type: Array, default: function () { return []; }, }, }, computed: { selected: { get() { return this.parentSelected; }, set(newVal) { this.$emit("update-data", newVal); }, }, }, }; </script> |
vueのドキュメントを見ると、v-model
を使った実装をよく見かけますが、子コンポーネントの場合はその実装を行うことができません。なぜならprops
で送ったデータに対して直接変更を行うとエラーになるからです。
子コンポーネントに変数を送った場合、基本的にはcomputed
を一枚かませて利用してください。
VeeValidateを使ったバリデーション
以下のコマンドをmy-app
フォルダ内で実行してください。
1 |
npm install vee-validate --save |
@/main.jsに以下をコピペして追加してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import Vue from "vue"; import App from "./App.vue"; import router from "./router"; import vuetify from "./plugins/vuetify"; import { extend, ValidationObserver, ValidationProvider, setInteractionMode, } from "vee-validate"; import * as rules from "vee-validate/dist/rules"; import { messages } from "vee-validate/dist/locale/en.json"; Vue.config.productionTip = false; Object.keys(rules).forEach((rule) => { extend(rule, { ...rules[rule], message: messages[rule], }); }); Vue.component("ValidationProvider", ValidationProvider); Vue.component("ValidationObserver", ValidationObserver); setInteractionMode("aggressive"); new Vue({ router, vuetify, render: (h) => h(App), }).$mount("#app"); |
@/views/Validation.vueを作成し、以下をコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
<template> <div class="validation"> <ValidationObserver ref="observer" v-slot="{ invalid }"> <v-form> <ValidationProvider name="Name" rules="required|alpha|max:10" v-slot="{ errors }" > <v-text-field v-model="name" :counter="10" :error-messages="errors" label="Name" required ></v-text-field> </ValidationProvider> <ValidationProvider name="Number" rules="required|numeric|max:4" v-slot="{ errors }" > <v-text-field v-model="num" :counter="4" :error-messages="errors" label="Number" required ></v-text-field> </ValidationProvider> <ValidationProvider name="Radio" rules="required" v-slot="{ errors }"> <v-radio-group v-model="radioGroup" :mandatory="false" :error-messages="errors" > <v-radio label="No" :value="false"></v-radio> <v-radio label="Yes" :value="true"></v-radio> </v-radio-group> </ValidationProvider> <v-btn class="mr-4" @click="submit" :disabled="invalid"> submit </v-btn> <v-btn class="mr-4" @click="check"> check </v-btn> <v-btn @click="clear"> clear </v-btn> </v-form> </ValidationObserver> </div> </template> <script> export default { name: "Validation", data: () => ({ name: "", num: "", radioGroup: null, errors: null, }), methods: { submit() { this.$refs.observer.validate(); alert( `name: ${this.name}\nnum: ${this.num}\nradioGroup: ${this.radioGroup}` ); }, check() { const error = []; if (!this.isAlphaOnly(this.name)) error.push(this.name); if (!this.isNumber(this.num)) error.push(this.num); if (!this.isBool(this.radioGroup)) error.push(this.radioGroup); const errorMessage = error.map((value) => { return `${value} is invalid.\n`; }); if (error.length > 0) alert(errorMessage); }, clear() { this.name = ""; this.num = ""; this.radioGroup = null; this.$refs.observer.reset(); }, isAlphaOnly(value) { try { return !value.match(/[^a-z]/gi); } catch (error) { return false; } }, isNumber(value) { try { return typeof value === "number"; } catch (error) { return false; } }, isBool(value) { try { return typeof value === "boolean"; } catch (error) { return false; } }, }, }; </script> |
Javascriptの頻出繰り返し構文
@/views/JavascriptMethod.vueを作成し、以下をコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
<template> <div id="JavascriptMethod"> <h3>CowFilter</h3> {{ filterMethod }} <h3>map</h3> {{ mapMethod }} <h3>forEach</h3> {{ forEachMethod }} <h3>find</h3> {{ findMethod }} <h3>some</h3> {{ someMethod }} <h3>for in</h3> {{ forInMethod }} <h3>for of</h3> {{ forOfMethod }} <h3>Object.keys</h3> {{ objectKeysMethod }} <h3>Object.values</h3> {{ objectValuesMethod }} </div> </template> <script> export default { name: "JavascriptMethod", data: () => ({ data: [ { id: 0, name: "dog" }, { id: 1, name: "cat" }, { id: 2, name: "cow" }, { id: 3, name: "cow" }, ], objectData: { a: "somestring", b: 42, c: false, }, }), computed: { filterMethod: function () { return this.data.filter((item) => { return item.name === "cow"; }); }, mapMethod: function () { return this.data.map((item, index) => { return { id: item.id * 2, name: item.name, index: index }; }); }, forEachMethod: function () { const result = []; this.data.map((item, index) => { result.push({ id: item.id, name: item.name, index: index }); }); return result; }, findMethod: function () { return this.data.find((item) => { return item.name === "cow"; }); }, someMethod: function () { const result = []; this.data.some((item, index) => { if (item.name === "cow") { return true; } result.push(index); }); return result; }, forInMethod: function () { const result = []; for (const key in this.data) { result.push(this.data[key]); } return result; }, forOfMethod: function () { const result = []; for (const item of this.data) { result.push(item.name); } return result; }, objectKeysMethod: function () { return Object.keys(this.objectData); }, objectValuesMethod: function () { return Object.values(this.objectData); }, }, }; </script> |