明暗模式切换

提示

在 Bootstrap 中 允许你在明暗模式之间切换。可以使用 data-bs-theme 属性来实现它。 你还可以创建自己的颜色模式。

AdminLTE 原生支持 Bootstrap 5.3 颜色模式(浅色、深色和自动)。自 4.1 起,切换器作为 ColorMode 模块内置于 adminlte.js 中——你不再需要将脚本复制到页面中。

工作原理
  • 所选模式保存在 localStorage 中,键名为 lte-theme。
  • auto 遵循操作系统的 prefers-color-scheme,并在操作系统偏好发生变化时实时更新。
  • 解析后的模式以 data-bs-theme="light|dark" 的形式应用于 <html>,因此所有 Bootstrap 和 AdminLTE 组件都会自动适配。

模式按以下顺序从三个来源解析:

  1. 访客已存储的选择 —— localStorage.lte-theme,在他们点击切换开关时写入。这是他们本人在此设备上的点击,因此优先级最高。
  2. 你的页面所声明的主题 —— 服务端返回时 <html> 上的 data-bs-theme。用它来根据 cookie 或用户记录渲染每位用户的偏好;它能在操作系统偏好变化后依然保留。
  3. 操作系统偏好 —— prefers-color-scheme,在上述两者都未表达选择时实时跟随。

仅能识别 light、dark 和 auto。data-bs-theme 中的自定义 Bootstrap 主题名不是 ColorMode 能解析的模式,因此会被忽略 —— 参见下文 选择退出。

标记

在任何位置添加带有 data-bs-theme-value 的切换按钮即可——模块会自动绑定它们。可选的 data-lte-theme-icon 元素用作当前选择的状态指示器(演示版在顶栏触发器中使用了它们):

<li class="nav-item dropdown">
  <a
    class="nav-link"
    href="#"
    id="bd-theme"
    aria-label="Toggle color scheme"
    data-bs-toggle="dropdown"
    aria-expanded="false"
  >
    <i class="bi bi-sun-fill" data-lte-theme-icon="light"></i>
    <i class="bi bi-moon-fill d-none" data-lte-theme-icon="dark"></i>
    <i class="bi bi-circle-half d-none" data-lte-theme-icon="auto"></i>
  </a>
  <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme">
    <li>
      <button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
        <i class="bi bi-sun-fill me-2"></i>
        明亮
        <i class="bi bi-check-lg ms-auto d-none"></i>
      </button>
    </li>
    <li>
      <button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="false">
        <i class="bi bi-moon-fill me-2"></i>
        暗黑
        <i class="bi bi-check-lg ms-auto d-none"></i>
      </button>
    </li>
    <li>
      <button type="button" class="dropdown-item d-flex align-items-center active" data-bs-theme-value="auto" aria-pressed="true">
        <i class="bi bi-circle-half me-2"></i>
        自动
        <i class="bi bi-check-lg ms-auto d-none"></i>
      </button>
    </li>
  </ul>
</li>

该模块会在每个 [data-bs-theme-value] 按钮上同步维护 active 类、aria-pressed 状态以及 .bi-check-lg 勾选标记。

JavaScript API
import { ColorMode } from "admin-lte"

const colorMode = new ColorMode()

colorMode.getPreferredTheme() // "light" | "dark" | "auto" —— 生效的选择
colorMode.getStoredTheme()    // 访客所选择的内容,若无则为 null
colorMode.getMarkupTheme()    // 页面在 <html> 上声明的内容,若无则为 null
colorMode.setTheme("dark")    // 应用 + 持续 + 同步切换

// 响应变化(文档触发)
document.addEventListener("changed.lte.color-mode", (event) => {
  console.log(event.detail.theme)    // 用户所选择的内容:"light" | "dark" | "auto"
  console.log(event.detail.resolved) // 实际应用的内容:    "light" | "dark"
})
防止主题错误闪烁

该模块在 DOM 就绪后运行,因此页面还应在首次绘制之前,通过在 <head> 中添加一小段内联代码来应用存储的主题(这是唯一必须保持内联的部分——参见 #6043):

<script>
  (() => {
    "use strict"
    const root = document.documentElement
    if (root.getAttribute("data-lte-color-mode") === "off") return
    let stored = null
    try { stored = localStorage.getItem("lte-theme") } catch {}
    const authored = root.getAttribute("data-bs-theme")
    let resolved = "light"
    if (stored === "dark" || stored === "light") resolved = stored
    else if (authored === "dark" || authored === "light") resolved = authored
    else if (matchMedia("(prefers-color-scheme: dark)").matches) resolved = "dark"
    root.setAttribute("data-bs-theme", resolved)
    root.style.colorScheme = resolved
    if (resolved !== authored) root.setAttribute("data-lte-theme-resolved", "")
  })()
</script>

它遵循与模块相同的优先级,因此你在服务端渲染的主题不会在绘制前被覆盖。最后一行很关键:它标记了一个由该代码片段自行推算出的值,这样模块就不会把它误认为是你的页面所声明的主题,从而停止跟随操作系统偏好。

服务端渲染的主题

如果你在服务端存储每位用户的偏好,将它渲染到 <html> 上,模块就会保留它 —— 在加载时,以及在操作系统偏好变化时。

<html lang="en" data-bs-theme="dark">

它仍然只是一个默认值:访客点击切换开关的那一刻,他们的选择就会被持久化,并从那时起在该设备上优先。当你希望服务端的值重新接管时,请从 localStorage 中清除 lte-theme。

选择退出

拥有自己主题方案的应用 —— 无论是自定义 Bootstrap 主题,还是你自己的切换器 —— 可以完全关闭该模块:

<html lang="en" data-lte-color-mode="off">

此后 ColorMode 永远不会写入 data-bs-theme:加载时不会,点击 [data-bs-theme-value] 切换开关时不会,操作系统偏好变化时也不会。上面的内联代码片段也会遵循这一点,因此在首次绘制之前也不会有任何东西触碰你的主题。你自己的代码始终完全掌控 <html data-bs-theme>。

区域颜色模式

data-bs-theme 不仅可以在 <html> 上使用,也可以在任何元素上使用——例如,在整体为浅色布局中,让侧边栏保持深色:

<aside class="app-sidebar" data-bs-theme="dark">...</aside>