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