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 />

最终效果

相关推荐
志尊宝3 天前
Vue3 零基础每日笔记(055):组件里正确使用 store——storeToRefs 解构与 $patch 批量修改
笔记·vue·html·前端开发·软件开发
yzy853 天前
Vue中下载或打开文件的JavaScript方法
前端·javascript·vue
溪语流沙5 天前
Django + Vue电商项目第001讲:开篇|注册登录加增删改查,那不是电商
redis·python·mysql·docker·typescript·django·vue
程序员阿黄5 天前
基于 Django 与 Vue 3 的智能实验室预约系统设计与实现
后端·python·mysql·django·vue·毕设
.Hypocritical.5 天前
Vue CLI(vue-cli)和 Vite 超详细对比
vue
志尊宝6 天前
Vue3 零基础每日笔记(040):Vite 创建 Vue3 + TS 项目——企业标配从这一篇开始
笔记·vue·html·前端开发·软件开发
凤城老人6 天前
从零手写开源私有云盘|Flask+Vue3+Electron全栈网盘,单容器一键部署
python·docker·electron·vue
球球不吃虾6 天前
Nuxt在使用过程中的一些小总结(二)
前端·vue·nuxt
志尊宝6 天前
Vue3 零基础每日笔记(038):亲手封装 useDebounceFn 与 useThrottleFn——高频事件的流量阀
前端·javascript·vue·html·vue3
愛芳芳7 天前
基于 Electron + Vue3 的仿 PC 微信客户端项目实战
前端·javascript·css·elementui·typescript·electron·vue