web制作でよく使用するVuex自作モジュール3選


ここ数ヶ月、webサイトをつくときはVueまたはVuePressを使用しています。
いくつか作ってみてほぼ必ず必要になってるVuexの自作モジュールがあるので3つほどご紹介

とりあえずこの3つをVuexつかって管理して必要なコンポーネントでmapState
などすると実装がシンプルになるような気がします。

## とりあえずindex.js

store/index.jsとかつくってとりあえず置いておく。基本は用途ごとにネームスペースを切る想定。


```index.js
import Vue from 'vue'
import Vuex from 'Vuex'

const state = {
}

const modules = {

}

const mutations = {

}

const actions = {

}

const store = new Vuex.Store({
  state,
  modules,
  mutations,
  actions,
})

export default store;
```


## レスポンシブ、画面サイズに関するモジュール

レスポンシブでウェブサイトを作っているとウインドウサイズの情報が欲しくなったり、
モバイルでは必要だけどPCでは必要ないみたいなことが頻繁に起こります。
windowに関する情報はstoreで管理してます。

store/module-window.js

```module-window.js
const mobileThreshold = 769;
const minWidth = 1280;

const decideIsPc = (w)=>{
  if(w < mobileThreshold){
    return false;
  }
  return true;
}

const getWindowSize = ()=>{
  let w = window.innerWidth
  let h = window.innerHeight
  if(w >= mobileThreshold) w = Math.max(minWidth, w);
  return {
    w: w,
    h: h
  }
}


const defaultState = typeof window !== 'undefined' ? {
  size: getWindowSize(),
  isPc: decideIsPc(window.innerWidth)
} : {
  size: {w: 999999, h: 999999},
  isPc: true,
}

const state = defaultState;

const mutations = {
  update(state){
    const size = getWindowSize();
    state.size = size
    state.isPc = decideIsPc(size.w);
  },
}


export default {
  namespaced: true,
  state,
  mutations
}
```

VuePressでビルドする用(おそらくNuxtでも同じ)に`typeof window`とかで条件分岐しているため
やや冗長になってますが、やっていることは`mutation`の`update`でウインドウサイズ取得して
サイズを更新、ついでにモバイルかどうかも変別して更新しているだけです。


store/index.jsにモジュールをついかするのと、(どこに書いても問題ないが)window resizeをフックする
部分もここに書いてしまっています。

```index.js

~
import ModuleWindow from './module-window'

~

const modules = {
  window: ModuleWindow,
}

~

if(typeof window !== 'undefined'){

  window.addEventListener('resize', ()=>{
    store.commit('window/update')
  })

}
```

storeのisPcはよく使うのでなんならmixinにしてもいいかもしれません。

```.js
import {mapState} from 'Vuex'
Vue.mixin({
  computed:{
    ...mapState('window', {$isPc: 'isPc'}),
  }
})
```

## スクロール位置に関するモジュール

ウインドウサイズと同じくスクロール位置に関してもたまに必要になるので
ほとんど同じだけれど作っておくと便利かもしれません。

store/module-scroll.js

```module-scroll.js
const state = {
  top: 0,
  left: 0
}

const mutations = {
  update(state){
    const elem = document.documentElement || document.body
    const top = elem.scrollTop
    const left = elem.scrollLeft
    state.top = top
    state.left = left
  }
}

const actions = {

}

const getters = {

}

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}
```

updateでスクロール位置調べてstate更新してるだけ。
updateを呼び出すのをウインドウと同じくstore/index.jsに書いておきます。

```index.js

~
import ModuleScroll from './module-scroll'

~

const modules = {
  scroll: ModuleScroll,
}

~

if(typeof window !== 'undefined'){

  window.addEventListener('scroll', ()=>{
    store.commit('scroll/update')
  })

}
```

## モーダルウインドウに関するモジュール

モーダルウインドウってつくるのめんどくさいですよね。
状態をVuexで管理すれば幾分ましな気持ちで実装できるんじゃないかと

```module-modal.js
const state = {
  isShow: false,
}

const mutations = {
  show(state) {
    document.body.style.overflow = 'hidden'
    state.isShow = true
    
  },
  hide(state) {
    document.body.style.overflow = 'auto'
    state.isShow = false
  },
}

const actions = {


}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
```

任意のコンポーネントでshow/hideを呼び出して、モーダルウインドウにしたいコンポーネントを
isShowと`v-if`で実装するということをしています。
bodyのoverflowのスタイルを変更しているのは背景をfixさせておくためのやつです。
これだけだとios safariではカバーしきれてないのでとりあえずというところですが
この件に関しては別の話題。

modulesに追加するところは省略


## おわりに

いかがだったでしょうか。特別なことをしているわけじゃないですが
なにか参考になる所があればと思います。
むしろみなさんどうしているんだろう。