クイック エンジニアリングブログ

株式会社クイック Web事業企画開発本部のエンジニアリングチームが運営する技術ブログです。

Nuxt3 + Vuetifyでライトモード・ダークモードを切り替える機能を実装した話

こんにちは。新卒入社3年目ソフトウェアエンジニアのほっしーです。先日、プロジェクトを異動して業務でNuxt.jsとVuetifyを使い始めました。今回は業務でライトモード・ダークモードの切り替え機能を実装した際の話について記事にしました。

モード切り替え用stateの実装

まずはじめにライトモード・ダークモードの状態保持と切り替えを行うstateを作成しました。リアクティブな値(isDarkMode)を保持したいのですが、isDarkModeはコンポーネント間で共有する値のためrefではなくuseStateを使用しております。全体像は以下の通りです。

type ModeType = 'light' | 'dark';

export default function useMode() {

  const isDarkMode = useState('isDarkMode', () => false);

  const toggleMode = () => {
    isDarkMode.value = !isDarkMode.value;
  }

  const getCurrentMode = (): ModeType => {
    return isDarkMode.value ? 'dark' : 'light';
  }

  return {
    toggleMode,
    getCurrentMode,
  }
}

こちらのuseModeを各pageで呼び出してgetCurrentMode()から現在のテーマを取得します。ライトモード・ダークモードはtoggleMode()で切り替えます。

<template>
  <v-app :theme="getCurrentMode()">
    <button @click="toggleMode"></button>
  </v-app>
</template>

<script setup>
const { toggleMode, getCurrentMode } = useMode();
</script>

ComputedRefの導入

useModeをレビューに出したところ「現在のテーマを関数で取得する必要はあるのか?」という話になりました。isDarkModeとthemeで状態を二重に管理するのは不恰好だと思いgetCurrentMode()から現在のテーマを取得していたのですが、以下のような書き方にすることで状態はisDarkModeで管理しつつthemeでもリアクティブな値を保持できるようになりました。

type ModeType = 'light' | 'dark';

export default function useMode() {

  const isDarkMode = useState('isDarkMode', () => false);

  const toggleMode = () => {
    isDarkMode.value = !isDarkMode.value;
  }

  const theme: ComputedRef<ModeType> = computed((): ModeType => {
    return isDarkMode.value ? 'dark' : 'light';
  })

  return {
    toggleMode,
    theme,
  }
}

各ページでは以下のように呼び出します。少しスマートになりましたね。

<template>
  <v-app :theme="theme">
    <button @click="toggleMode"></button>
  </v-app>
</template>

<script setup>
const { toggleMode, theme } = useMode();
</script>

useThemeの導入

二度目のレビューで「現在のテーマをisDarkModeで保持してるけどそもそもVuetifyで提供されてないのかな?」とご指摘をいただきました。私の調査不足だったのですが、VuetifyではuseThemeというAPIが提供されていました。こちらを「const theme = useTheme()」のように使うことで現在のテーマを取得することができます。上記の書き方を踏まえてuseModeを以下のように書き換えました。

export default function useMode() {

  const theme = useTheme();

  const isDarkMode: ComputedRef<boolean> = computed((): boolean => {
    return theme.global.name.value === 'dark';
  })

  const toggleMode = (): void => {
    theme.global.name.value = isDarkMode.value ? 'light' : 'dark';
  }

  return {
    toggleMode,
  }
}

また、各ページで呼び出す際には「:theme="theme"」を書く必要がなくなりました。これでライトモード・ダークモードの状態保持と切り替えを行う機能は完成です。

<template>
  <v-app>
    <button @click="toggleMode"></button>
  </v-app>
</template>

<script setup>
const { toggleMode } = useMode();
</script>

まとめ

今回はVuetifyでライトモード・ダークモードを切り替える機能を実装しました。もしこれから同じような機能を実装する方がいればお役に立てると幸いです。


\\『真のユーザーファーストでマーケットを創造する』仲間を募集中です!! // 919.jp