首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Agavi MVC 框架實戰 (三-2):自訂母版頁、CSS 隔離與後台介面美化

     編輯:PHP 綜合知識

為什麼需要獨立後台母版頁?

  • **視覺區隔**:管理員一眼辨識當前在後台,降低誤操作風險。
  • **佈局差異**:後台常需側邊欄導航、麵包屑、資料表格、彈窗等專用元件。
  • **資源隔離**:後台專用 CSS/JS 不汙染前台,便於獨立打包、快取、版本控制。

建立 AdminMaster.php (完整版)

<?php // app/templates/AdminMaster.php ?>
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex, nofollow">
  <base href="<?= $ro->getBaseHref() ?>" />
  <title><?= $t->getAttribute('_title', 'Admin') ?> - WASP Admin</title>
  <!-- 前台共用樣式 -->
  <link rel="stylesheet" href="/css/default.css">
  <!-- 後台專用樣式 (後載入,優先級較高) -->
  <link rel="stylesheet" href="/css/admin.css">
  <!-- 圖示字體 -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6/css/all.min.css">
</head>
<body class="admin-body">
  <!-- Header -->
  <header class="admin-header">
    <div class="brand">
      <a href="<?= $ro->gen('admin.dashboard') ?>">
        <img src="/images/logo-admin.svg" alt="WASP Admin" height="32">
      </a>
    </div>
    <nav class="admin-nav">
      <a href="<?= $ro->gen('admin.listing.index') ?>"><i class="fas fa-car"></i> 車輛管理</a>
      <a href="<?= $ro->gen('admin.user.index') ?>"><i class="fas fa-users"></i> 用戶管理</a>
      <a href="<?= $ro->gen('admin.settings') ?>"><i class="fas fa-cog"></i> 設定</a>
      <a href="<?= $ro->gen('admin.logout') ?>" class="btn-logout"><i class="fas fa-sign-out-alt"></i> 登出</a>
    </nav>
  </header>

  <!-- Sidebar + Content -->
  <div class="admin-container">
    <aside class="admin-sidebar">
      <ul class="sidebar-menu">
        <li><a href="<?= $ro->gen('admin.listing.index') ?>"><i class="fas fa-list"></i> 所有車輛</a></li>
        <li><a href="<?= $ro->gen('admin.listing.create') ?>"><i class="fas fa-plus"></i> 新增車輛</a></li>
        <li><a href="<?= $ro->gen('admin.user.index') ?>"><i class="fas fa-users"></i> 銷售商帳號</a></li>
      </ul>
    </aside>
    <main class="admin-content">
      <div class="page-header">
        <h1><?= $t->getAttribute('_title', '儀表板') ?></h1>
        <ol class="breadcrumb">
          <li><a href="<?= $ro->gen('admin.dashboard') ?>">首頁</a></li>
          <li class="active"><?= $t->getAttribute('_title', '') ?></li>
        </ol>
      </div>
      <!-- 子視圖內容注入點 -->
      <?= $inner ?>
    </main>
  </div>

  <footer class="admin-footer">
    <p>© <?= date('Y') ?> WASP Admin. Powered by <a href="https://agavi.org">Agavi</a>.</p>
  </footer>

  <!-- 後台專用 JS -->
  <script src="/js/admin.js"></script>
</body></html>

admin.css 關鍵片段 (SCSS 結構)


// admin.scss
$sidebar-width: 240px;
$header-height: 56px;
$primary: #2c3e50;
$accent: #3498db;

.admin-body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
  font-family: 'Noto Sans TC', system-ui, sans-serif;
  background: #f4f6f9;
}

.admin-header {
  height: $header-height;
  background: $primary;
  color: #fff;
  display: flex;
  align-items: center;
  padding: 0 1.5rem;
  position: sticky;
  top: 0;
  z-index: 100;
  .brand img { height: 28px; }
  .admin-nav {
    margin-left: auto;
    display: flex; gap: 1rem; align-items: center;
    a { color: rgba(255,255,255,0.8); text-decoration: none; padding: 0.5rem 1rem; border-radius: 4px; transition: background .2s; }
    a:hover, a:focus { background: rgba(255,255,255,0.1); color: #fff; }
    .btn-logout { background: #e74c3c; }
  }
}

.admin-container {
  display: flex;
  flex: 1;
  overflow: hidden;
}

.admin-sidebar {
  width: $sidebar-width;
  background: #fff;
  border-right: 1px solid #e1e4e8;
  padding: 1rem 0;
  overflow-y: auto;
  .sidebar-menu {
    list-style: none; padding: 0; margin: 0;
    li a { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 1.5rem; color: #333; text-decoration: none; transition: background .2s; }
    li a:hover, li a.active { background: #e8f0fe; color: $accent; }
    i { width: 20px; text-align: center; }
  }
}

.admin-content {
  flex: 1;
  padding: 2rem;
  overflow-y: auto;
  .page-header { margin-bottom: 1.5rem; }
  .breadcrumb { font-size: 0.875rem; color: #666; }
  .breadcrumb a { color: $accent; }
}

.admin-footer {
  padding: 1rem;
  text-align: center;
  color: #999;
  font-size: 0.875rem;
  border-top: 1px solid #e1e4e8;
  background: #fff;
}

/* 響應式: 768px 以下側邊欄收合為抽屜 */
@media (max-width: 768px) {
  .admin-sidebar {
    position: fixed; left: 0; top: $header-height; bottom: 0;
    transform: translateX(-100%);
    transition: transform .3s ease;
    z-index: 200;
    &.open { transform: translateX(0); }
  }
  .admin-content { padding-top: calc(#{$header-height} + 1rem); }
}

編譯與部署

# 專案根目錄
npm init -y
npm install -D sass
# package.json scripts
"build:css": "sass pub/css/admin.scss pub/css/admin.css --style=compressed --no-source-map"
# 執行
npm run build:css

上線前執行 `npm run build:css` 產出壓縮 CSS,配合 Agavi 快取機制 (`output_cache`)。

View 套用母版頁

<?php
// app/modules/Admin/views/ListingIndexSuccessView.class.php
class Admin_ListingIndexSuccessView extends AgaviHtmlView
{
    public function setupHtml()
    {
        $this->setLayout('AdminMaster');
        $this->setAttribute('_title', '車輛管理');
    }
}

進階:動態側邊欄選單 (根據角色)

<?php // AdminMaster.php 片段 ?>
<ul class="sidebar-menu">
  <?php $user = $this->getContext()->getSession()->getAttribute('admin_user'); ?>
  <li><a href="<?= $ro->gen('admin.listing.index') ?>"><i class="fas fa-car"></i> 車輛列表</a></li>
  <?php if ($user['role'] === 'admin'): ?>
    <li><a href="<?= $ro->gen('admin.user.index') ?>"><i class="fas fa-users"></i> 用戶管理</a></li>
    <li><a href="<?= $ro->gen('admin.settings') ?>"><i class="fas fa-cog"></i> 系統設定</a></li>
  <?php endif; ?>
</ul>

總結

  • `$this->setLayout('AdminMaster')` 在 View 中指定母版,Agavi 會在 `app/templates/` 尋找對應 `.php` 檔案。
  • 母版頁透過 `$inner` 變數注入子視圖內容,並可存取 `$t` (模板變數)、`$ro` (路由器)、`$this->getContext()` (完整上下文)。
  • CSS/JS 依賴管理建議使用 **Webpack/Vite + Sass**,產出 `admin.css`/`admin.js` 放入 `pub/`,母版頁以 ``/`
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved