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

Yii2 主題 (Theme) 機制深度解析:pathMap 映射、繼承鏈、資源發布、動態切換

     編輯:PHP 相關知識

Yii2 主題 (Theme) 機制深度解析:pathMap 映射、繼承鏈、資源發布、動態切換

Yii2 `yii\base\Theme` 透過**路徑映射替換**實現視圖主題化:將原視圖路徑 (如 `@app/views`) 映射到主題目錄 (如 `@app/themes/basic`),若主題目錄缺檔則回退原視圖,形成**繼承鏈**。本文深度解析配置、核心方法、資源處理、動態切換與多主題架構。

1. 基礎配置

<?php
// config/main.php
return [
    'components' => [
        'view' => [
            'theme' => [
                'class' => 'yii\base\Theme',
                'pathMap' => [
                    '@app/views' => ['@app/themes/basic', '@app/themes/default'],
                    '@app/modules' => '@app/themes/default/modules',
                    '@app/widgets' => '@app/themes/default/widgets',
                ],
                'baseUrl' => '@web/themes/basic',    // CSS/JS/圖片公開 URL
                'basePath' => '@app/themes/basic',   // 資源實體路徑
            ],
        ],
    ],
];
?>

2. pathMap 映射規則與繼承鏈

  • 鍵:原始路徑別名 (必須以 `@` 開頭或絕對路徑)。
  • 值:單一路徑字串,或**陣列** (依序嘗試,形成繼承鏈)。
  • 替換邏輯:`applyTo($path)` 將 `$path` 中符合鍵的前綴替換為值,檢查檔案是否存在,存在即返回,否則嘗試下一個值,全部失敗返回原路徑。

範例:多層繼承

pathMap => [
    '@app/views' => [
        '@app/themes/dark',      // 第 1 優先:深色主題專屬視圖
        '@app/themes/basic',     // 第 2 優先:基礎主題覆蓋
        '@app/themes/default',   // 第 3 優先:框架預設視圖
    ],
]

請求 `@app/views/site/index.php` → 依序檢查:

  1. `@app/themes/dark/site/index.php` ✅ 存在 → 使用
  2. 不存在 → 檢查 `@app/themes/basic/site/index.php`
  3. 不存在 → 檢查 `@app/themes/default/site/index.php`
  4. 全不存在 → 回退 `@app/views/site/index.php`

3. 核心方法原始碼解析

init() 初始化

public function init() {
    parent::init();
    if (empty($this->pathMap)) {
        if (($basePath = $this->getBasePath()) === null) {
            throw new InvalidConfigException('The "basePath" property must be set.');
        }
        // 相容舊版:無 pathMap 時以 basePath 對應應用基礎路徑
        $this->pathMap = [Yii::$app->getBasePath() => [$basePath]];
    }
}

applyTo($path) 路徑替換核心

public function applyTo($path) {
    $path = FileHelper::normalizePath($path);
    foreach ($this->pathMap as $from => $tos) {
        $from = FileHelper::normalizePath(Yii::getAlias($from)) . DIRECTORY_SEPARATOR;
        if (strpos($path, $from) === 0) {
            $n = strlen($from);
            foreach ((array) $tos as $to) {
                $to = FileHelper::normalizePath(Yii::getAlias($to)) . DIRECTORY_SEPARATOR;
                $file = $to . substr($path, $n);
                if (is_file($file)) return $file;
            }
        }
    }
    return $path; // 全部失敗回退原路徑
}

4. 資源發布

  • baseUrl:公開訪問 URL 前綴 (如 `/themes/basic`),結尾**不加**斜線。
  • basePath:資源實體目錄 (如 `@app/themes/basic`)。
  • 視圖中使用:``
  • 或註冊 AssetBundle:`$this->theme->baseUrl` 會自動注入 AssetBundle 的 `baseUrl`。

5. 動態切換主題

<?php
// 控制器/基類
public function beforeAction($action) {
    $theme = Yii::$app->request->get('theme', 'basic');
    $allowed = ['basic', 'dark', 'mobile'];
    if (in_array($theme, $allowed)) {
        Yii::$app->view->theme = [
            'class' => 'yii\base\Theme',
            'pathMap' => [
                '@app/views' => ["@app/themes/$theme", '@app/themes/default'],
            ],
            'baseUrl' => "@web/themes/$theme",
            'basePath' => "@app/themes/$theme",
        ];
        // 可存入 Session/Cookie 持久化
    }
    return parent::beforeAction($action);
}
?>

6. 進階:模組/擴充套件專屬主題

pathMap => [
    '@app/views' => ['@app/themes/basic', '@app/themes/default'],
    '@vendor/yiisoft/yii2-jui/views' => '@app/themes/basic/jui', // 覆蓋 JUI 視圖
    '@app/modules/admin/views' => ['@app/themes/admin', '@app/themes/basic/modules/admin'],
]

7. 常見問題排查

現象原因解決
主題不生效pathMap 鍵別名錯誤、大小寫不符 (Linux 區分大小寫)用 `Yii::getAlias('@app/views')` 驗證實際路徑
CSS/JS 404baseUrl/basePath 未配置或資源未發布檢查 `baseUrl` 指向正確 Web 可訪問目錄
繼承鏈失效值為字串而非陣列,或順序錯誤確保值為陣列,優先級高→低
模組視圖未主題化pathMap 缺少模組路徑映射添加 `@app/modules/ModuleID/views` 映射

延伸閱讀

更多 Yii2 主題進階:AssetBundle 整合主題、動態編譯 Less/Sass/PostCSS、多租戶主題隔離、主題市場架構設計、視圖渲染效能優化 (快取 `applyTo` 結果)、測試主題切換功能,請參考本站專題系列。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved