Nuxt3 实战 (八):优雅的实现暗黑主题模式

前言

Nuxt3 中要实现暗黑模式,需要用到一个库:color-mode,它可以帮助我们很轻易地实现暗黑模式切换。

具体使用

  1. 安装 @nuxtjs/color-mode 依赖:
powershell 复制代码
pnpm add @nuxtjs/color-mode -D
  1. 打开 nuxt.config.ts 配置文件注入依赖:
ts 复制代码
export default defineNuxtConfig({
  modules: ['@nuxtjs/color-mode']
})
  1. 你也可以根据项目实际情况自定义配置,以下是一些默认配置:
ts 复制代码
import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
  modules: ['@nuxtjs/color-mode'],
  colorMode: {
    preference: 'system', // default value of $colorMode.preference
    fallback: 'light', // fallback value if not system preference found
    hid: 'nuxt-color-mode-script',
    globalName: '__NUXT_COLOR_MODE__',
    componentName: 'ColorScheme',
    classPrefix: '',
    classSuffix: '-mode',
    storageKey: 'nuxt-color-mode'
  }
})

具体的使用文档:NuxtColorMode

按钮模式

  1. src/components 中新建 ColorMode/index.vue 文件:
html 复制代码
 <script setup lang="ts">
 const colorMode = useColorMode()

 // 切换模式
 const setColorMode = () => {
   colorMode.value = colorMode.value === 'dark' ? 'light' : 'dark'
 }

 // 判断是否支持 startViewTransition API
 const enableTransitions = () =>
   'startViewTransition' in document &&
   window.matchMedia('(prefers-reduced-motion: no-preference)').matches

 // 切换动画
 async function toggleDark({ clientX: x, clientY: y }: MouseEvent) {
   const isDark = colorMode.value === 'dark'

   if (!enableTransitions()) {
     setColorMode()
     return
   }

   const clipPath = [
     `circle(0px at ${x}px ${y}px)`,
     `circle(${Math.hypot(
       Math.max(x, innerWidth - x),
       Math.max(y, innerHeight - y)
     )}px at ${x}px ${y}px)`
   ]

   await document.startViewTransition(async () => {
     setColorMode()
     await nextTick()
   }).ready

   document.documentElement.animate(
     { clipPath: !isDark ? clipPath.reverse() : clipPath },
     {
       duration: 300,
       easing: 'ease-in',
       pseudoElement: `::view-transition-${!isDark ? 'old' : 'new'}(root)`
     }
   )
 }
 </script>

 <template>
   <el-tooltip
     :content="`切换${$colorMode.value === 'dark' ? '白天' : '黑夜'}模式`"
     placement="bottom"
   >
     <el-button
       circle
       text
       @click="toggleDark"
     >
       <Icon
         :name="$colorMode.value === 'dark' ? 'i-heroicons-moon-solid' : 'i-heroicons-sun-solid'"
         class="h-5 w-5"
       />
     </el-button>
   </el-tooltip>
 </template>

 <style>
 ::view-transition-old(root),
 ::view-transition-new(root) {
   animation: none;
   mix-blend-mode: normal;
 }

 ::view-transition-old(root),
 .dark::view-transition-new(root) {
   z-index: 1;
 }

 ::view-transition-new(root),
 .dark::view-transition-old(root) {
   z-index: 9999;
 }
 </style>
  1. 在需要的地方加载组件:
html 复制代码
<ColorMode />

最终效果

相关推荐
Cult Of14 小时前
Alicea Wind的个人网站开发日志(2)
开发语言·python·vue
Byron07071 天前
从多端割裂到体验统一:基于 Vue 生态的跨端架构落地实战
vue·多端
计算机程序设计小李同学1 天前
基于 Spring Boot + Vue 的龙虾专营店管理系统的设计与实现
java·spring boot·后端·spring·vue
沐墨染1 天前
Vue实战:自动化研判报告组件的设计与实现
前端·javascript·信息可视化·数据分析·自动化·vue
奔跑的呱呱牛1 天前
viewer-utils 图片预览工具库
javascript·vue·react
Cult Of2 天前
Alicea Wind的个人网站开发日志(1)
python·vue
Polaris_YJH2 天前
使用Vue3+Vite+Pinia+elementUI搭建初级企业级项目
前端·javascript·elementui·vue
Mr Xu_2 天前
【Vue3 + ECharts 实战】正确使用 showLoading、resize 与 dispose 避免内存泄漏
前端·信息可视化·vue·echarts
换日线°2 天前
前端炫酷展开效果
前端·javascript·vue
IT北辰3 天前
基于Vue3+python+mysql8.0的财务凭证录入系统,前后端分离完整版(可赠送源码)
python·vue