ブログの投稿ログ

2021年
9月
8月
7月
6月

Vuexでダークモード実装

今回はVueでライトモード/ダークモードを実現しました。 それらを切り替える際、複数箇所に影響がで他ので単純に親要素のクラスを切り替えるだけでは対応仕切らない為、Vuexで状態管理しつつ実行しています。

今日のコード

codesandbox


App.vue

<template>
// 状態に応じたクラスを付与
  <div id="app" :class="selectMode">
    // light/darkボタンの入っているHeaderコンポーネント
    <Header />
    <img alt="Vue logo" src="./assets/logo.png" width="25%" />
    <HelloWorld msg="Hello Vue in CodeSandbox!" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";
import Header from "./components/Header";

export default {
  name: "App",
  components: {
    HelloWorld,
    Header,
  },
  computed: {
    selectMode() {
      // storeで状態管理した値を出力(lightかdark)
      return [`mode-${this.$store.state.mode}`];
    },
  },
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  height: 100%;
}
body {
  margin: 0;
}
// light時のクラス
.mode-light {
  background: #fff;
  color: #000;
}
// dark時のクラス
.mode-dark {
  background: #000;
  color: #fff;
}
</style>

親コンポーネントであるAppコンポーネント内に最終的な処理を書いて行っています。
store内のstateに今現在のライトかダークかの状態が格納されていて、
その状態に応じてクラスを変更しているのがApp.vueの中身となります。


Header.vue

<template>
  <div class="mode-wrap">
    <div
      // stateのmodeの値がlightであればis-activeを追加
      :class="[{ 'is-active': $store.state.mode == 'light' }]"
      class="light"
      // クリックイベントを定義
      @click="changeMode('light')"
    ></div>
    <div
      // stateのmodeの値がdarkであればis-activeを追加
      :class="[{ 'is-active': $store.state.mode == 'dark' }]"
      class="dark"
      // クリックイベントを定義
      @click="changeMode('dark')"
    ></div>
  </div>
</template>

<script>
export default {
  name: "Header",
  methods: {
      // 仮引数にはdark/lightが入っている
    changeMode(mode) {
      // storeへ関数と仮引数をディスパッチ
      this.$store.dispatch("changeMode", mode);
    },
  },
};
</script>

store/index.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
  // stateを定義
  state: {
    mode: "light"
  },

  actions: {
    // vue側のクラスをアクションへ定義
    changeMode({ commit }, mode) {
      commit("changeMode", { mode: mode });
    }
  },

  mutations: {
    changeMode(state, { mode }) {
      // actionで定義した値を元にstateへlightかdarkか送る
      state.mode = mode;
    }
  }
});

export default store;

以上です!