VueCLIでアプリ作成(アドレス帳)②
①でSideNav.vueでストアのstateにdispathメソッドでsrc/App.vueでアイコンにクリックメソッドを実装しましたが、mapActionsメソッドを使う方法に変更
vuex mapActionsの利用
mapActionsメソッドはコンポーネントにストアのアクションメソッドを組み込む。
src/App.vue
①mapActionインポート import { mapActions } from 'vuex'
②methods内にmapActionsメソッドを記述
...mapActions(['使用したいストアアクション名'])
③ openSideMenu()メソッドを削除
openSideMenu(){
this.$store.dispatch('toggleSideMenu')
},
④ツールバーアイコンのクリックメソッドを...mapActionsで指定したストアアクション名に変更 @click="toggleSideMenu"
<template>
<v-app>
<v-toolbar app>
<v-toolbar-side-icon @click="toggleSideMenu"></v-toolbar-side-icon>
<v-toolbar-title class="headline text-uppercase">
<span>マイドレス帳</span>
</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<SideNav></SideNav>
<v-content>
<Addresses/>
</v-content>
</v-app>
</template>
<script>
import { mapActions } from 'vuex'
import Addresses from './components/Addresses.vue'
import SideNav from './components/SideNav.vue'
export default {
name: 'App',
components: {
Addresses,
SideNav
},
data () {
return {
//
}
},
methods:{
...mapActions(['toggleSideMenu'])
}
}
</script>
連絡先一覧ページ作成
src/App.vueに<router-view></router-view>を追加(ページごとに設定したコンポーネントを表示)
<v-content>
<router-view></router-view>
<Addresses/>
</v-content>
src/components/Addresses.vueをページとして表示させる
①src/components/Addresses.vue→src/views配下に移動。
src/App.vueでAddressesコンポーネントを使用していた場合は削除(タグ、インポート、コンポーネント登録)
②src/views/Addresses.vueを書き換え
<template>
<v-container text-xs-center justify-center>
<v-layout row wrap>
<v-flex xs12>
<h1>連絡先一覧</h1>
</v-flex>
<v-flex xs12 mt-5 justify-center>
<v-data-table :headers='headers' :items='addresses'>
<template v-slot:items="props">
<td class="text-xs-left">{{ props.item.name }}</td>
<td class="text-xs-left">{{ props.item.tel }}</td>
<td class="text-xs-left">{{ props.item.email }}</td>
<td class="text-xs-left">{{ props.item.address }}</td>
</template>
</v-data-table>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
export default {
data () {
return {
headers: [
{ text: '名前', value: 'name' },
{ text: '電話番号', value: 'tel' },
{ text: 'メールアドレス', value: 'email' },
{ text: '住所', value: 'address' }
],
addresses: [
{
name: '友人1',
tel: '090-0000-1111',
email: 'sample1@mail.com',
address: '東京都渋谷区'
},
{
name: '友人2',
tel: '090-2222-3333',
email: 'sample2@mail.com',
address: '東京都品川区'
}
]
}
}
}
</script>
vuetifyのテーブルでheadersとaddresseにdataで登録した内容が入るように記述
③Addresses.vueへのルート設定
src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import Addresses from "../views/Addresses.vue";
import AddressForm from "../views/AddressForm.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: Home,
},
{
path: "/addresses",
name: "addresses",
component: Addresses,
},
{
path: "/addresses/:address_id?/edit",
name: "address_edit",
component: AddressForm,
},
{
path: "/about",
name: "about",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue"),
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
addresses.vueをimport 、routesを設置したら、http://localhost:8080/addresses で確認。
Addresses.vueをSideNavに追加
src/components/SideNav.vue
<template>
<v-navigation-drawer v-model="$store.state.drawer" absolute temporary>
<v-list class="pa-1">
<v-list-tile avatar>
<v-list-tile-avatar>
<img src="https://avatars2.githubusercontent.com/u/1363954?s=460&v=4">
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title>Kazuya Kojima</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
<v-list class="pt-0" dense>
<v-divider></v-divider>
<v-list-tile v-for="item in items" :key="item.title" :to="item.link">
<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
</template>
<script>
export default {
data () {
return {
items: [
{ title:'ホーム', icon:'home', link:{ name:'home'}},
{ title: '連絡先一覧', icon: 'list',link:{name:'addresses'}}
]
}
}
}
</script>
①<v-layout wrap style="height: 200px;">を削除
②dataのitemsの連絡先オブジェクトにリンクを追加 { title: '連絡先一覧', icon: 'list',link:{name:'addresses'}}
③dataのitemsにホームオブジェクトも追加{ title:'ホーム', icon:'home', link:{ name:'home'}},
④templateのv-listに:to=”item.link"を追加してリンクさせる
連絡先追加画面作成
src/views/AddressForm.vueを追加
<template>
<v-container text-xs-center>
<v-layout row wrap justify-center>
<v-flex xs12>
<h1>連絡先編集</h1>
</v-flex>
<v-flex xs5 mt-5>
<v-card>
<v-card-text>
<v-form>
<v-text-field v-model="address.name" label="名前"></v-text-field>
<v-text-field v-model="address.tel" label="電話番号"></v-text-field>
<v-text-field v-model="address.email" label="メールアドレス"></v-text-field>
<v-text-field v-model="address.address" label="住所"></v-text-field>
<v-btn @click="$router.push({ name: 'addresses' })">キャンセル</v-btn>
<v-btn color="info">保存</v-btn>
</v-form>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
export default {
data () {
return {
address: {}
}
}
}
</script>
①dataにaddress:{ } 空のオブジェクトを用意して、template内のテキストフィールドに入力した内容が入るようにv-modelをaddress.name、address.tel、address.email、address.addressに設定
<v-text-field v-model="address.name" label="名前"></v-text-field>
<v-text-field v-model="address.tel" label="電話番号"></v-text-field>
<v-text-field v-model="address.email" label="メールアドレス"></v-text-field>
<v-text-field v-model="address.address" label="住所"></v-text-field>
②キャンセル・保存ボタンを用意
キャンセルでアドレス一覧に戻るように設定。
template内では$routerというルーターオブジェクトにアクセス可能。pushメソッドでページを遷移できる。ルート名で遷移先を指定。
<v-btn @click="$router.push({ name: 'addresses' })">キャンセル</v-btn>
src/views/AddressForm.vueへのroute追加
src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import Addresses from "../views/Addresses.vue";
import AddressForm from "../views/AddressForm.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/addresses",
name: "addresses",
component: Addresses,
},
{
path: "/addresses/:address_id?/edit",
name: "address_edit",
component: AddressForm,
},
{
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue"),
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
①AddressForm.vueをインポート
②routesに追加
path: "/addresses/:address_id?/edit"
:address_id?にはaddressのidが入る想定。例えばidが1なら「/addresses/1/edit」になる。
:から始まるパスを含めることで、コンポーネントでパラメータとして受け取れる。
?で終わることでパラメータをオプション扱いにできる(idがない場合もこのrouteが使われる)
③アドレス一覧からAddressForm.vueにリンクするボタンを設置
src/views/Addresses.vue
<v-flex xs12 mt-5 text-xs-right>
<router-link :to="{ name:'address_edit' }">
<v-btn color="info">連絡先追加</v-btn>
</router-link>
</v-flex>
<template>
<v-container text-xs-center justify-center>
<v-layout row wrap>
<v-flex xs12>
<h1>連絡先一覧</h1>
</v-flex>
<v-flex xs12 mt-5 text-xs-right>
<router-link :to="{ name:'address_edit' }">
<v-btn color="info">連絡先追加</v-btn>
</router-link>
</v-flex>
<v-flex xs12 mt-5 justify-center>
<v-data-table :headers='headers' :items='addresses'>
<template v-slot:items="props">
<td class="text-xs-left">{{ props.item.name }}</td>
<td class="text-xs-left">{{ props.item.tel }}</td>
<td class="text-xs-left">{{ props.item.email }}</td>
<td class="text-xs-left">{{ props.item.address }}</td>
</template>
</v-data-table>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
export default {
data () {
return {
headers: [
{ text: '名前', value: 'name' },
{ text: '電話番号', value: 'tel' },
{ text: 'メールアドレス', value: 'email' },
{ text: '住所', value: 'address' }
],
addresses: [
{
name: '友人1',
tel: '090-0000-1111',
email: 'sample1@mail.com',
address: '東京都渋谷区'
},
{
name: '友人2',
tel: '090-2222-3333',
email: 'sample2@mail.com',
address: '東京都品川区'
}
]
}
}
}
</script>
連絡先追加機能 (ストアへの保存)
src/store/index.jsでストアへの保存
①stateにaddressesという配列を用意 addresses:[]
②actionsにaddAddressメソッドを追加してmutaionsでaddAddressメソッドに渡す。第2引数でコンポーネントから値を受け取れる。
actions: {
toggleSideMenu({ commit }) {
commit("toggleSideMenu");
},
addAddress({ commit }, address) {
commit("addAddress", address);
},
},
③mutaionsのaddAddressメソッドでstate.addressesにaddressを追加
mutations: {
toggleSideMenu(state) {
state.drawer = !state.drawer;
},
addAddress(state, address) {
state.addresses.push(address);
},
},
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
drawer: false,
addresses: [],
},
mutations: {
toggleSideMenu(state) {
state.drawer = !state.drawer;
},
addAddress(state, address) {
state.addresses.push(address);
},
},
actions: {
toggleSideMenu({ commit }) {
commit("toggleSideMenu");
},
addAddress({ commit }, address) {
commit("addAddress", address);
},
},
});
AddressForm.vueでmapActionsを使用
①mapActionsをインポート
import {mapActions} from 'vuex'
②methodsでaddAddressストアアクションを指定
methods:{
...mapActions(['addAddress'])
}
③methodsでsubmitメソッドを実装。
・フォームで入力された値がストアのaddAddressに格納。this.addAddress(this.address)
・保存後に連絡先一覧へのリンク this.$router.push({name:'addresses'})
・フォームのリセット this.address = {}
methods:{
submit(){
this.addAddress(this.address)
this.$router.push({name:'addresses'})
this.address = {}
},
...mapActions(['addAddress'])
}
アドレス一覧のデータをストアのデータに置き換え
src/Addresses.vue
①dataのaddressesは空の配列にする
data () {
return {
headers: [
{ text: '名前', value: 'name' },
{ text: '電話番号', value: 'tel' },
{ text: 'メールアドレス', value: 'email' },
{ text: '住所', value: 'address' }
],
addresses: []
}
}
②createdでインスタンスが作成されたタイミングでストアのデータが入るように設定
created(){
this.addresses =this.$store.state.addresses
},
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
drawer: false,
addresses: [],
},
mutations: {
toggleSideMenu(state) {
state.drawer = !state.drawer;
},
addAddress(state, address) {
state.addresses.push(address);
},
},
actions: {
toggleSideMenu({ commit }) {
commit("toggleSideMenu");
},
addAddress({ commit }, address) {
commit("addAddress", address);
},
},
});