在现代网页设计中,深色主题不仅仅是一种潮流,更是一种突破。
它不仅为夜间编程爱好者提供了视觉舒适感,还为用户界面增添了一丝优雅。
基础设置
修改 tailwind.config.js
文件中的 darkMode
配置使用 class
模式:
export default {
darkMode: 'class', // 深色模式的关键配置!
content: [
"./resources/**/*.blade.php",
"./resources/**/*.js",
],
theme: {
extend: {},
},
plugins: [],
}
在 welcome.blade.php
文件中添加 Alpine.js
指令:
<body class="antialiased"
x-data="{darkMode: false}"
:class="{'dark': darkMode === true }">
-
x-data
指令用于设置组件的初始状态。 -
:class="{'dark': darkMode === true }"
指令用于根据darkMode
的值动态添加或移除dark
类。
并且引入 app.css
和 app.js
文件:
@vite(['resources/css/app.css', 'resources/js/app.js'])
创建手动深色主题切换组件
创建一个主题切换按钮组件 resources/views/components/switch-theme.blade.php
:
<button @click="darkMode=!darkMode" type="button" class="relative inline-flex flex-shrink-0 h-6 mr-5 transition-colors duration-200 ease-in-out border-2 border-transparent rounded-full cursor-pointer bg-zinc-200 dark:bg-zinc-700 w-11 focus:outline-none focus:ring-2 focus:ring-neutral-700 focus:ring-offset-2" role="switch" aria-checked="false">
<span class="sr-only">Switch Theme</span>
<span class="relative inline-block w-5 h-5 transition duration-500 ease-in-out transform translate-x-0 bg-white rounded-full shadow pointer-events-none dark:translate-x-5 ring-0">
<!-- 太阳图标 -->
<span class="absolute inset-0 flex items-center justify-center w-full h-full transition-opacity duration-500 ease-in opacity-100 dark:opacity-0 dark:duration-100 dark:ease-out" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-sun w-4 h-4 text-neutral-700" width="24" height="24" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"></path>
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7"></path>
</svg>
</span>
<!-- 月亮图标 -->
<span class="absolute inset-0 flex items-center justify-center w-full h-full transition-opacity duration-100 ease-out opacity-0 dark:opacity-100 dark:duration-200 dark:ease-in" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-moon w-4 h-4 text-neutral-700" width="24" height="24" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</span>
</span>
</button>
解决页面刷新问题
使用 Alpine.js
的 persist
插件来保持主题状态:
yarn add -D @alpinejs/persist
更新 resources/js/app.js
:
import './bootstrap';
import Alpine from 'alpinejs'
import persist from '@alpinejs/persist'
window.Alpine = Alpine
Alpine.plugin(persist)
Alpine.start()
解决闪烁问题
在 resources/css/app.css
中添加:
@tailwind base;
@tailwind components;
@tailwind utilities;
[x-cloak] { display: none !important; }
更新 body
标签,添加 x-clock
属性:
<body class="antialiased"
x-cloak
x-data="{darkMode: $persist(false)}"
:class="{'dark': darkMode === true }">
-
x-cloak
指令用于在 Alpine.js 初始化完成之前隐藏元素。 -
x-data="{darkMode: $persist(false)}"
指令用于设置darkMode
的初始状态,并使用persist
插件来保持其值。该值被存储在浏览器的localStorage
中的_x_darkMode
键中。 -
:class="{'dark': darkMode === true }"
指令用于根据darkMode
的值动态添加或移除dark
类。
Dusk 测试
如果还没有安装 Laravel Dusk,可以通过以下命令安装:
composer require --dev laravel/dusk
php artisan dusk:install
创建一个新的 Dusk 测试文件 tests/Browser/ThemeSwitchTest.php
:
<?php
use Laravel\Dusk\Browser;
it('can switch between light and dark theme', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
// 确认初始状态是亮色主题
->assertMissing('.dark')
// 点击主题切换按钮
->click('@theme-switch')
->pause(500) // 等待动画完成
// 确认主题设置被保持
->assertPresent('.dark')
// 再次点击切换回亮色主题
->click('@theme-switch')
->pause(500)
// 确认回到亮色主题
->assertMissing('.dark');
});
});
it('theme preference persists after page reload', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
// 切换到深色主题
->click('@theme-switch')
->pause(500)
// 刷新页面
->refresh()
// 确认主题设置被保持
->assertPresent('.dark');
});
});
为了让测试能够正常运行,需要在主题切换按钮上添加 dusk
属性:
<button dusk="theme-switch" @click="darkMode=!darkMode" type="button" class="relative inline-flex flex-shrink-0 h-6 mr-5 transition-colors duration-200 ease-in-out border-2 border-transparent rounded-full cursor-pointer bg-zinc-200 dark:bg-zinc-700 w-11 focus:outline-none focus:ring-2 focus:ring-neutral-700 focus:ring-offset-2" role="switch" aria-checked="false">
<!-- ... 按钮内容保持不变 ... -->
</button>
这些测试用例会验证:
- 主题切换按钮能够正常工作
- 主题设置在页面刷新后能够保持
- 深色主题类名正确添加和移除
最后,需要在 DuskTestCase
中重写 newBrowser
方法:
protected function newBrowser($driver): Browser
{
return new Browser($driver, new ElementResolver($driver, ''));
}
运行测试:
php artisan dusk tests/Browser/ThemeSwitchTest.php
运行Dusk测试之前,请确保:
- 已经安装并配置好 Laravel Dusk
- Chrome 驱动已更新到最新版本
- 开发服务器正在运行