다크모드 구현하기

Project Diary/Vue (Roblox WebSite)

Vue.js와 Vuex를 사용하여 다크모드를 구현하는 방법 기록


다크모드는 사용자가 웹사이트나 애플리케이션을 어두운 테마로 전환할 수 있는 기능입니다. 이를 통해 시각적 피로를 줄이고, 다양한 환경에서의 가독성을 향상시킬 수 있습니다.

 

1. Vuex 설정

먼저, 다크모드 상태를 관리하기 위해 Vuex를 설정합니다. Vuex는 Vue.js 애플리케이션에서 상태 관리를 효율적으로 할 수 있게 해주는 라이브러리입니다.

 

Vuex 설정 (store/index.js 및 store/dark/index.js)

store/index.js

import Vue from "vue";
import Vuex from "vuex";
import VuexPersistence from "vuex-persist";
import modDark from "@/store/dark"; // 다크모드 모듈 추가

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    modDark, // 다크모드 모듈 추가
  },
  plugins: [new VuexPersistence({ storage: window.localStorage }).plugin],
});

 


store/dark/index.js

export default {
  state: {
    dark: false, // 다크모드 초기 상태
  },
  mutations: {
    on__ChangeDark(state) {
      state.dark = !state.dark; // 다크모드 상태 변경
    },
  },
  getters: {
    fnGetDark(state) {
      return state.dark; // 다크모드 상태 반환
    },
  },
};

 

 

2. 다크모드 스타일 설정

다음으로, 다크모드와 관련된 스타일을 설정합니다. 다크모드일 때와 아닐 때의 배경색과 텍스트 색상을 지정합니다.

 

style.css

:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;

  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;

  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}

.dark {
  background: radial-gradient(circle, #dfdfdf 1px, transparent 1px), white;
  background-position: 0 0, 25px 25px;
  background-size: 2rem 2rem;
}

@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }
}

 

 

3. 다크모드 토글 버튼 구현

다음으로, 다크모드를 토글할 수 있는 버튼을 구현합니다. 이 버튼을 클릭하면 Vuex를 통해 다크모드 상태가 변경됩니다.

 

Header.vue

<template>
  <header id="header">
    <nav id="header__nav">
      <h1 class="header__logo">
        <router-link to="/"><img :src="imgUrl" alt="roblox logo" /></router-link>
      </h1>
      <ul class="header__menuBar">
        <li>
          <p class="dark dark__mode" :class="{ light: changeDarkMode }" @click="onOff">
            <i class="fa-solid fa-moon"></i>
            <span>{{ $t("[3].darkmode") }}</span>
          </p>
        </li>
      </ul>
    </nav>
  </header>
</template>

<script>
export default {
  name: "Header",
  data() {
    return {
      imgUrl: "./assets/images/roblox_logo_white_new.svg",
    };
  },
  methods: {
    onOff() {
      this.$store.commit("on__ChangeDark"); // 다크모드 상태 변경
    },
  },
  computed: {
    changeDarkMode() {
      return this.$store.getters.fnGetDark; // 다크모드 상태 가져오기
    },
  },
};
</script>

<style scoped>
.header__menuBar .dark {
  //생략
.header__menuBar .light {
  //생략
}
</style>

 

  • 다크모드 상태 변경 : onOff 메소드에서 this.$store.commit("on__ChangeDark")를 호출하여 다크모드 상태를 변경합니다.
  • 다크모드 상태 가져오기 : changeDarkMode 계산된 속성에서 Vuex 게터를 통해 다크모드 상태를 가져옵니다.
  • 다크모드 상태 적용 : 이제 다크모드 상태를 기반으로 스타일을 적용합니다. 각 컴포넌트에서 다크모드 상태에 따라 스타일을 변경할 수 있습니다.

 

App.vue

<template>
  <div :class="{ dark: changeDarkMode }">
    <Header class="header"></Header>
    <div id="app__contents">
      <router-view></router-view>
    </div>
    <Footer></Footer>
  </div>
</template>

<script>
import Header from "./components/layout/Header.vue";
import Footer from "./components/layout/Footer.vue";
export default {
  name: "App",
  components: {
    Header,
    Footer,
  },
  computed: {
    changeDarkMode() {
      return this.$store.getters.fnGetDark; // 다크모드 상태 가져오기
    },
  },
};
</script>

<style scoped>
#app__contents {
  padding-top: 165px;
}
.dark {
  background: radial-gradient(circle, #dfdfdf 1px, transparent 1px), white;
  background-position: 0 0, 25px 25px;
  background-size: 2rem 2rem;
}
</style>
  • 다크모드 상태 기반 스타일 적용: :class="{ dark: changeDarkMode }"를 사용하여 다크모드 상태에 따라 클래스를 적용합니다.
  • 계산된 속성 사용: changeDarkMode 계산된 속성에서 Vuex 게터를 통해 다크모드 상태를 가져와서 스타일을 변경합니다.

 

이로써 Vue.js와 Vuex를 사용하여 다크모드를 구현하는 방법을 살펴보았습니다. 다크모드 상태를 Vuex로 관리하고, 각 컴포넌트에서 이를 기반으로 스타일을 동적으로 변경하여 사용자에게 더 나은 시각적 경험을 제공할 수 있습니다.