Client/VueJS 3.0

Vue3) Tailwindcss darkmode, user system prefers-color-scheme

Juzdalua 2022. 8. 4. 13:19

먼저 다크모드를 사용해보자. 

셋팅을 하고 토글버튼을 만든다.

 

// tailwind.config.js

module.exports = {
	...
	darkMode: 'class'
    ...
};

class로 darkMode를 지정해준다.

public/index.html에서 html 태그에 class="dark"가 들어가면 다크모드가 적용된다.

 

헤더에 토글버튼을 만들어보자.

// Header.vue

<template>
  <header class="fixed left-0 right-0 z-30 flex items-center justify-between bg-white dark:bg-gray-900 dark:border-gray-600 topp-0 h-100 border-b-1 ">
    <div class="flex items-center">
      <button v-if="state.darkMode === 'dark'" @click="onClickDarkMode('light')" id="light" class="p-10 border-none rounded-full dark:hover:bg-gray-700 hover:bg-gray-200">
        <img src="~@/assets/images/icon-filter-dark.svg" class="w-30 h-30"/>
      </button>
      <button v-else @click="onClickDarkMode('dark')" id="dark" class="p-10 border-none rounded-full dark:hover:bg-gray-700 hover:bg-gray-200">
        <img src="~@/assets/images/icon-filter-light.svg" class="w-30 h-30"/>
      </button>
    </div>
  </header>
</template>

<script lang="ts">
import { computed, defineComponent, onMounted, reactive } from "vue";
import { useRouter } from "vue-router";
import { useStore } from "vuex";

export default defineComponent({
  components: {
  },
  setup() {
    const store = useStore();
    const router = useRouter();
    const state = reactive({
      darkMode: computed(() => store.getters['utils/mode']),
    });

    onMounted(() => {

    });

    const onClickDarkMode = (id:string) => {
      const root = document.querySelector('html');
      if(id === 'dark'){
        root!.classList.add('dark');
        window.localStorage.setItem('mode', 'dark');
        store.dispatch('utils/mode', 'dark');
      } else if(id === 'light'){
        root!.classList.remove('dark');
        window.localStorage.setItem('mode', 'light');
        store.dispatch('utils/mode', 'light');
      };

    };

    return {
      state,
      onMounted,
      onClickDarkMode,
    };
  },
});
</script>

사용자의 모드 설정을 무기한 저장하기 위해 세션스토리지를, 전역변수로 활용하기 위해 스토어를 사용했다.

토글버튼을 누르면 html 태그에 dark 클래스를 추가할지 삭제할지 구현했다.

 

이제 저장한 스토리지와 스토어를 활용하여 페이지가 로딩될 때를 처리해보자.

// App.vue

<script lang="ts">
import { computed, defineComponent, reactive, onMounted } from "vue";
import { useStore } from "vuex";
import ModalArea from "./ModalArea.vue";

export default defineComponent({
  components: {
    ModalArea,
  },
  setup() {
    const store = useStore();
    const state = reactive({
      darkMode: computed(() => store.getters["utils/mode"]),
    })

    onMounted(() => {
      const root = document.querySelector('html');

      const userDefaultMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
      if(userDefaultMode){
        store.dispatch('utils/mode', 'dark');
        root!.classList.add('dark');
      };

      const mode = window.localStorage.getItem('mode');
      if(mode){
        store.dispatch('utils/mode', mode);
      }

      if(state.darkMode === 'dark'){
        root!.classList.add('dark');
      } else {
        root!.classList.remove('dark');
      };

    });

    return {
      onMounted,
    };
  },
});
</script>

루트 페이지인 App.vue에서 전역으로 발동시켰다.

중간에 prefers-color-schme는 유저가 시스템을 다크모드로 설정해놓았다면 이를 체크하고 자동으로 다크모드로 변환해주는 코드를 구현했다.

 

그럼 이제 다크모드를 적용해보자.

<template>
  <aside class="fixed left-0 z-10 h-screen bg-white dark:text-gray-200 dark:bg-gray-900 w-300 border-r-1 dark:border-gray-600">

    <div class="flex flex-col px-20 py-10 mt-130">
      <router-link @click="onClickMenu('dashboard')" class="flex items-center p-8 rounded-md text-lgdark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-700" to="/discover">
        <img v-if="state.darkMode === 'dark'" src="~@/assets/images/icon_home_dark.svg" class="mr-20"/>
        <img v-else src="~@/assets/images/icon_home_light.svg" class="mr-20"/>
        <span class="dark:text-gray-200">Dashboard</span>
      </router-link>
    </div>
  </aside>
</template>

class에 동일하게 css를 작성하면 되는데, 다크모드에서 적용할 항목들은 pre-fix로 dark:를 달아주면 된다.

만약 이미지나 다른 컴포넌트를 보여주고 싶다면 state에 현재 모드 store를 불러오고 이를 활용하여 v-if로 구분지었다.

'Client > VueJS 3.0' 카테고리의 다른 글

Tailwindcss) customizing - jit, px  (0) 2022.08.02
Css) Video tag autoplay가 안될 때  (0) 2022.07.28
Vue3) Youtube iframe 영상 재생  (0) 2022.07.12
Vue3) Tailwind css 적용하기  (0) 2022.07.11
CSS) Box Shadow  (0) 2022.07.07