常见模式 & 方案

针对每个管理仪表盘中都会出现的模式,提供可直接复制粘贴的解决方案。每个方案都假定您已经按照入门指南操作,并拥有一个可用的 AdminLTE 页面作为基础。

带图标、徽章和标题的多级侧边栏

演示仪表盘使用的就是这个模式。使用 .nav-header 对区域进行分组,使用嵌套的 .nav-treeview 列表表示项目层级深度,使用 .navbar-badge 显示计数。

<aside class="app-sidebar bg-body-secondary shadow" data-bs-theme="dark">
  <div class="sidebar-brand">
    <a href="/" class="brand-link">
      <span class="brand-text fw-light">我的仪表盘</span>
    </a>
  </div>
  <div class="sidebar-wrapper">
    <nav class="mt-2">
      <ul class="nav sidebar-menu flex-column" data-lte-toggle="treeview" role="menu">

        <li class="nav-header">首页</li>
        <li class="nav-item">
          <a href="/" class="nav-link active">
            <i class="nav-icon bi bi-speedometer"></i>
            <p>仪表盘</p>
          </a>
        </li>

        <li class="nav-item">
          <a href="#" class="nav-link">
            <i class="nav-icon bi bi-folder"></i>
            <p>
              项目
              <span class="badge text-bg-info ms-2">12</span>
              <i class="nav-arrow bi bi-chevron-right"></i>
            </p>
          </a>
          <ul class="nav nav-treeview">
            <li class="nav-item">
              <a href="#" class="nav-link"><i class="nav-icon bi bi-circle"></i><p>活跃</p></a>
            </li>
            <li class="nav-item">
              <a href="#" class="nav-link"><i class="nav-icon bi bi-circle"></i><p>归档</p></a>
            </li>
          </ul>
        </li>

        <li class="nav-header">报告</li>
        <li class="nav-item">
          <a href="#" class="nav-link">
            <i class="nav-icon bi bi-bar-chart"></i>
            <p>销售</p>
            <span class="badge text-bg-danger ms-auto">3</span>
          </a>
        </li>

      </ul>
    </nav>
  </div>
</aside>

要将当前页面标记为激活状态,请在服务端将 .active 类渲染到对应的 .nav-link 上。对于 SPA 框架,在路由变更时添加它。

从 JavaScript 高亮当前侧边栏项

如果您是一次性渲染侧边栏,并希望客户端路由高亮:

function setActiveSidebarItem(href) {
  document.querySelectorAll(".sidebar-menu .nav-link").forEach((el) => {
    el.classList.toggle("active", el.getAttribute("href") === href)
  })
}

// 路线变更通知
setActiveSidebarItem(window.location.pathname)
响应式数据表格

<table> 包裹在 .table-responsive 中,使其在窄视口下获得水平滚动条,而不是溢出卡片。

<div class="card">
  <div class="card-header">
    <h3 class="card-title">最近订单</h3>
  </div>
  <div class="card-body p-0">
    <div class="table-responsive">
      <table class="table table-striped align-middle mb-0">
        <thead>
          <tr>
            <th>#</th>
            <th>客户</th>
            <th>合计</th>
            <th>状态</th>
            <th class="text-end">操作</th>
          </tr>
        </thead>
        <tbody>
          <!-- rows -->
        </tbody>
      </table>
    </div>
  </div>
</div>

如需交互式排序/筛选/分页,请使用 Tabulator——演示中的 tables/data.html 有完整示例。

顶部栏中的用户下拉菜单
<li class="nav-item dropdown user-menu">
  <a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">
    <span class="d-none d-md-inline me-1">Jane Doe</span>
    <i class="bi bi-person-circle fs-5"></i>
  </a>
  <ul class="dropdown-menu dropdown-menu-end">
    <li>
      <a href="/profile" class="dropdown-item">
        <i class="bi bi-person me-2"></i>资料
      </a>
    </li>
    <li>
      <a href="/settings" class="dropdown-item">
        <i class="bi bi-gear me-2"></i>设置
      </a>
    </li>
    <li><hr class="dropdown-divider"></li>
    <li>
      <a href="/logout" class="dropdown-item text-danger">
        <i class="bi bi-box-arrow-right me-2"></i>退出
      </a>
    </li>
  </ul>
</li>

将此代码放在 .app-header 中的 <ul class="navbar-nav ms-auto"> 内部。

KPI 卡片(small-box)

大多数仪表盘顶部的彩色统计框:

<div class="row g-3">
  <div class="col-lg-3 col-6">
    <div class="small-box text-bg-primary">
      <div class="inner">
        <h3>150</h3>
        <p>新订单</p>
      </div>
      <i class="bi bi-cart small-box-icon" aria-hidden="true"></i>
      <a href="#" class="small-box-footer link-light">
        更多信息 <i class="bi bi-arrow-right"></i>
      </a>
    </div>
  </div>
  <!-- 重复 3 次,使用不同的数值和颜色 -->
</div>

text-bg-primary 替换为 text-bg-successtext-bg-warningtext-bg-danger 等。

面包屑 + 页面标题行

这是每个演示页面都使用的标准 .app-content-header 模式:

<div class="app-content-header">
  <div class="container-fluid">
    <div class="row">
      <div class="col-sm-6">
        <h3 class="mb-0">页面标题</h3>
      </div>
      <div class="col-sm-6">
        <ol class="breadcrumb float-sm-end">
          <li class="breadcrumb-item"><a href="/">首页</a></li>
          <li class="breadcrumb-item"><a href="/section">章节</a></li>
          <li class="breadcrumb-item active" aria-current="page">当前页</li>
        </ol>
      </div>
    </div>
  </div>
</div>
时间线

用于动态消息、审计日志或路线图视图:

<div class="timeline">
  <div>
    <i class="bi bi-envelope bg-info" aria-hidden="true"></i>
    <div class="timeline-item">
      <span class="time"><i class="bi bi-clock"></i> 12:05</span>
      <h3 class="timeline-header">
        <a href="#">Olivia</a> 给你发送一条消息
      </h3>
      <div class="timeline-body">
        嘿,我们明天10点能看一下第四季度的数字吗?
      </div>
      <div class="timeline-footer">
        <a class="btn btn-primary btn-sm">查看更多</a>
      </div>
    </div>
  </div>
  <!-- repeat -->
</div>

时间线组件位于 _timeline.scss 中,并有多种变体。完整集合请参见 /UI/timeline.html

直接聊天小部件

用于实时客户支持、团队聊天等的聊天风格卡片。包括联系人切换和消息气泡。

<div class="card direct-chat direct-chat-primary">
  <div class="card-header">
    <h3 class="card-title">聊天</h3>
    <div class="card-tools">
      <span class="badge text-bg-primary">3 new</span>
      <button type="button" class="btn btn-tool" data-lte-toggle="chat-pane" title="Contacts">
        <i class="bi bi-people-fill"></i>
      </button>
    </div>
  </div>
  <div class="card-body">
    <div class="direct-chat-messages">
      <div class="direct-chat-msg">
        <div class="direct-chat-infos clearfix">
          <span class="direct-chat-name float-start">Olivia</span>
          <span class="direct-chat-timestamp float-end">12:05</span>
        </div>
        <img class="direct-chat-img" src="/avatars/olivia.jpg" alt="" />
        <div class="direct-chat-text">嘿,准备好了吗?</div>
      </div>
      <div class="direct-chat-msg right">
        <div class="direct-chat-infos clearfix">
          <span class="direct-chat-name float-end">You</span>
          <span class="direct-chat-timestamp float-start">12:06</span>
        </div>
        <img class="direct-chat-img" src="/avatars/me.jpg" alt="" />
        <div class="direct-chat-text">是的,我准备好了!</div>
      </div>
    </div>
    <div class="direct-chat-contacts">
      <!-- 聊天面板切换时显示的联系人列表 -->
    </div>
  </div>
  <div class="card-footer">
    <form>
      <div class="input-group">
        <input type="text" class="form-control" placeholder="Message…" />
        <button type="submit" class="btn btn-primary">
          <i class="bi bi-send"></i>
        </button>
      </div>
    </form>
  </div>
</div>

如需完整的聊天页面应用,请参见演示中的 /pages/chat.html

响应布局/侧边栏变更

监听插件事件以与您自己的代码协调——例如,当侧边栏折叠时重新适配图表(使图表重新测量其容器宽度):

let chart = /* ApexCharts 实例 */

document.addEventListener("collapse.lte.push-menu", () => {
  // wait for the transition to finish (~300ms by default)
  setTimeout(() => chart.updateOptions({}), 350)
})

document.addEventListener("open.lte.push-menu", () => {
  setTimeout(() => chart.updateOptions({}), 350)
})

同样的模式适用于 Tabulator、FullCalendar 以及任何其他在初始化时读取容器宽度的库。

通过 fetch 将内容加载到卡片中
<div class="card" id="users-card">
  <div class="card-header">
    <h3 class="card-title">Users</h3>
    <div class="card-tools">
      <span class="spinner-border spinner-border-sm text-secondary d-none" id="users-spinner" role="status"></span>
    </div>
  </div>
  <div class="card-body p-0">
    <div id="users-body" class="text-secondary p-3">加载中&hellip;</div>
  </div>
</div>

<script>
  const spinner = document.getElementById("users-spinner")
  const body = document.getElementById("users-body")

  spinner.classList.remove("d-none")
  fetch("/api/users")
    .then((r) => r.text())
    .then((html) => { body.innerHTML = html })
    .catch(() => { body.textContent = "Failed to load." })
    .finally(() => spinner.classList.add("d-none"))
</script>
提交前确认破坏性操作

Bootstrap 模态框 + 一个简单的确认模式:

<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#confirmDelete">
  删除账户
</button>

<div class="modal fade" id="confirmDelete" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">删除账户?</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body">
        这将永久删除您的账户及所有相关数据,且无法恢复。
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
        <form action="/account/delete" method="POST" class="d-inline">
          <button type="submit" class="btn btn-danger">是的,删除它!</button>
        </form>
      </div>
    </div>
  </div>
</div>

颜色模式无障碍访问以及捆绑的 JS 会自动处理模态框内的 Escape 关闭、焦点陷阱和键盘导航。

接下来去哪里