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>

無題

画像2

連絡先一覧ページ作成

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 で確認。

画像3


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"を追加してリンクさせる

画像4

連絡先追加画面作成

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);
   },
 },
});

いいなと思ったら応援しよう!