はじめに
初めてvuetifyをnuxtで使ってドロワーの管理をvuexでやりたいのに、
公式とかはそういうの書いてなくて困ったのでメモです。
前提
nuxt 2.12.0
TypeScript済み
pug
vuex-module-decorators導入済み vuex-module-decoratorsの、導入については
僕のこの記事とか、
この人の記事を参考にしてください。
実装
実装は、vuetify公式のhttps://vuetifyjs.com/ja/getting-started/pre-made-layouts/ ここの、Baselineをそれぞれをcomponentに分割して、ドロワーの開閉をvuexで状態管理していきます。
layouts
v-app-bar、v-navigation-drawerをそれぞれAppBar, Navigationに分割しています。
<template lang="pug">
v-app#inspire
navigation
app-bar
nuxt
v-footer(color='indigo', app='')
span.white--text © System mun
</template>
<script lang="ts">
import {
Component,
Prop,
Vue
} from "nuxt-property-decorator"
const Navigation =()=> import('~/components/Navigation.vue')
const AppBar =()=> import('~/components/AppBar.vue')
@Component({
components: {
Navigation,
AppBar
}
})
export default class Default extends Vue {
}
</script>
<template lang="pug">
v-app-bar(app='', color='indigo', dark='')
v-app-bar-nav-icon(@click.stop='drawer')
v-toolbar-title Hoge
</template>
<script lang="ts">
import {
Component,
Prop,
Vue
} from "nuxt-property-decorator"
import { DrawerStore } from '~/store'
@Component({})
export default class AppBar extends Vue {
drawer() {
DrawerStore.setDrawer(!DrawerStore.drawer)
}
}
</script>
<template lang="pug">
v-navigation-drawer(v-model='drawer', app='')
v-list(dense='')
v-list-item(link='')
v-list-item-action
v-icon mdi-home
v-list-item-content
v-list-item-title Home
v-list-item(link='')
v-list-item-action
v-icon mdi-contact-mail
v-list-item-content
v-list-item-title Contact
</template>
<script lang="ts">
import {
Component,
Prop,
Vue
} from "nuxt-property-decorator"
import { DrawerStore } from '~/store'
@Component({})
export default class Navigation extends Vue {
get drawer(){
return DrawerStore.drawer
}
set drawer(val:any){
DrawerStore.setDrawer(val)
}
}
</script>
get,set drawerをやっておかないとハンバーガーアイコンをクリックしたときは正常に動作しますが、
ドロワーの領域外をクリックしたときにドロワーが閉じません。
必ず、computedのgetでstoreをreturnして、setでstoreにsetしてください。
storeは、
import { VuexModule, Module, Mutation } from 'vuex-module-decorators'
import Vuex from 'vuex'
const store = new Vuex.Store<any>({})
export interface DrawerState {
isDrawer: boolean
}
@Module({
stateFactory: true,
namespaced: true,
name: 'drawer',
store,
dynamic: true
})
export default class Drawer extends VuexModule implements DrawerState {
isDrawer: boolean = false
@Mutation
setDrawer(drawer: boolean) {
this.isDrawer = drawer
}
get drawer() {
return this.isDrawer
}
}
あんまり書いてないので、僕の勘違いなのかもしれないですが、
@Module()のなかのnameとファイル名が同じじゃないと正常な動作をしないような気がします。
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import Drawer from '~/store/drawer'
let DrawerStore: Drawer
function initialiseStores(store: Store<any>): void {
DrawerStore = getModule(Drawer, store)
}
export { initialiseStores, DrawerStore }
これで、drawerにDrawerStore としてアクセスできます。
おわり
公式のままでは、layoutsに全部そのままぶち込まないと動かないので、ちょっとぶさいくかと思いました。
あと、状態管理にvuex使いたいので。
こんな感じにしておけばcomponentsに分割できるし、layoutもすっきりするし。いいんじゃないですか。
typescriptで記載してるので、あれですが、すこし変えればJavaScriptでも同じようなことすればいいので、参考にはなるかと思います。