PHP的Yii架構中View視圖的使用進階_php技巧

來源:互聯網
上載者:User

視圖名

渲染視圖時,可指定一個視圖名或視圖檔案路徑/別名,大多數情況下使用前者因為前者簡潔靈活, 我們稱用名字的視圖為 視圖名.

視圖名可以依據以下規則到對應的視圖檔案路徑:

視圖名可省略副檔名,這種情況下使用 .php 作為擴充, 視圖名 about 對應到 about.php 檔案名稱;
視圖名以雙斜杠 // 開頭,對應的視圖檔案路徑為 @app/views/ViewName, 也就是說視圖檔案在 yii\base\Application::viewPath 路徑下找, 例如 //site/about 對應到 @app/views/site/about.php。
視圖名以單斜杠/開始,視圖檔案路徑以當前使用模組 的yii\base\Module::viewPath開始, 如果不存在模組,使用@app/views/ViewName開始,例如,如果當前模組為user, /user/create 對應成@app/modules/user/views/user/create.php, 如果不在模組中,/user/create對應@app/views/user/create.php。
如果 yii\base\View::context 渲染視圖 並且上下文實現了 yii\base\ViewContextInterface, 視圖檔案路徑由內容相關的 yii\base\ViewContextInterface::getViewPath() 開始, 這種主要用在控制器和小組件中渲染視圖,例如 如果上下文為控制器SiteController,site/about 對應到 @app/views/site/about.php。
如果視圖渲染另一個視圖,包含另一個視圖檔案的目錄以當前視圖的檔案路徑開始, 例如被視圖@app/views/post/index.php 渲染的 item 對應到 @app/views/post/item。
根據以上規則,在控制器中 app\controllers\PostController 調用 $this->render('view'), 實際上渲染@app/views/post/view.php 視圖檔案,當在該視圖檔案中調用 $this->render('_overview') 會渲染@app/views/post/_overview.php 視圖檔案。

視圖中訪問資料

在視圖中有兩種方式訪問資料:推送和拉取。

推送方式是通過視圖渲染方法的第二個參數傳遞資料,資料格式應為名稱-值的數組, 視圖渲染時,調用PHP extract() 方法將該數群組轉換為視圖可訪問的變數。 例如,如下控制器的渲染視圖程式碼推送2個變數到 report 視圖:$foo = 1 和 $bar = 2。

echo $this->render('report', [  'foo' => 1,  'bar' => 2,]);

拉取方式可讓視圖從yii\base\View視圖組件或其他對象中主動獲得資料(如Yii::$app), 在視圖中使用如下運算式$this->context可擷取到控制器ID, 可讓你在report視圖中擷取控制器的任意屬性或方法,如以下代碼擷取控制器ID。

The controller ID is: <?= $this->context->id ?>?>

推送方式讓視圖更少依賴內容物件,是視圖擷取資料優先使用方式, 缺點是需要手動構建數組,有些繁瑣,在不同地方渲染時容易出錯。

視圖間共用資料

yii\base\View視圖組件提供yii\base\View::params參數屬性來讓不同視圖共用資料。

例如在about視圖中,可使用如下代碼指定當前breadcrumbs的當前部分。

$this->params['breadcrumbs'][] = 'About Us';

在布局檔案(也是一個視圖)中,可使用依次加入到yii\base\View::params數組的值來 產生顯示breadcrumbs:

<?= yii\widgets\Breadcrumbs::widget([  'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],]) ?>

布局

布局是一種特殊的視圖,代表多個視圖的公用部分,例如,大多數Web應用共用相同的頁頭和頁尾, 在每個視圖中重複相同的頁頭和頁尾,更好的方式是將這些公用放到一個布局中, 渲染內容視圖後在合適的地方嵌入到布局中。

建立布局

由於布局也是視圖,它可像普通視圖一樣建立,布局預設儲存在@app/views/layouts路徑下, 模組中使用的布局應儲存在yii\base\Module::basePath模組目錄 下的views/layouts路徑下,可配置yii\base\Module::layoutPath來自訂應用或模組的布局預設路徑。

如下樣本為一個布局大致內容,注意作為樣本,簡化了很多代碼, 在實際中,你可能想添加更多內容,如頭部標籤,主菜單等。

<?phpuse yii\helpers\Html;/* @var $this yii\web\View *//* @var $content string 字串 */?><?php $this->beginPage() ?><!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8"/>  <?= Html::csrfMetaTags() ?>  <title><?= Html::encode($this->title) ?></title>  <?php $this->head() ?></head><body><?php $this->beginBody() ?>  <header>My Company</header>  <?= $content ?>  <footer>© 2014 by My Company</footer><?php $this->endBody() ?></body></html><?php $this->endPage() ?>

如上所示,布局產生每個頁面通用的HTML標籤,在<body>標籤中,列印$content變數, $content變數代表當yii\base\Controller::render()控制器渲染方法調用時傳遞到布局的內容視圖渲染結果。

大多數視圖應調用上述代碼中的如下方法,這些方法觸發關於渲染過程的事件, 這樣其他地方註冊的指令碼和標籤會添加到這些方法調用的地方。

  • yii\base\View::beginPage(): 該方法應在布局的開始處調用, 它觸發表明頁面開始的 yii\base\View::EVENT_BEGIN_PAGE 事件。
  • yii\base\View::endPage(): 該方法應在布局的結尾處調用, 它觸發表明頁面結尾的 yii\base\View::EVENT_END_PAGE 時間。
  • yii\web\View::head(): 該方法應在HTML頁面的<head>標籤中調用, 它產生一個預留位置,在頁面渲染結束時會被註冊的頭部HTML代碼(如,link標籤, meta標籤)替換。
  • yii\web\View::beginBody(): 該方法應在<body>標籤的開始處調用, 它觸發 yii\web\View::EVENT_BEGIN_BODY 事件並產生一個預留位置, 會被註冊的HTML代碼(如JavaScript)在頁面主體開始處替換。
  • yii\web\View::endBody(): 該方法應在<body>標籤的結尾處調用, 它觸發 yii\web\View::EVENT_END_BODY 事件並產生一個預留位置, 會被註冊的HTML代碼(如JavaScript)在頁面主體結尾處替換。

布局中訪問資料

在布局中可訪問兩個預定義變數:$this 和 $content,前者對應和普通視圖類似的yii\base\View 視圖組件 後者包含調用yii\base\Controller::render()方法渲染內容視圖的結果。

如果想在布局中訪問其他資料,必須使用視圖中訪問資料一節介紹的拉取方式, 如果想從內容視圖中傳遞資料到布局,可使用視圖間共用資料一節中的方法。

使用布局

如控制器中渲染一節描述,當控制器調用yii\base\Controller::render() 方法渲染視圖時,會同時使用布局到渲染結果中,預設會使用@app/views/layouts/main.php布局檔案。

可配置yii\base\Application::layout 或 yii\base\Controller::layout 使用其他布局檔案, 前者管理所有控制器的布局,後者覆蓋前者來控制單個控制器布局。 例如,如下代碼使 post 控制器渲染視圖時使用 @app/views/layouts/post.php 作為布局檔案, 假如layout 屬性沒改變,控制器預設使用 @app/views/layouts/main.php 作為布局檔案。

namespace app\controllers;use yii\web\Controller;class PostController extends Controller{  public $layout = 'post';  // ...}

對於模組中的控制器,可配置模組的 yii\base\Module::layout 屬性指定布局檔案應用到模組的所有控制器。

由於layout 可在不同層級(控制器、模組,應用)配置,在幕後Yii使用兩步來決定控制器實際使用的布局。

第一步,它決定布局的值和上下文模組:

如果控制器的 yii\base\Controller::layout 屬性不為空白null,使用它作為布局的值, 控制器的 yii\base\Controller::module模組 作為上下文模組。
如果 yii\base\Controller::layout 為空白,從控制器的祖先模組(包括應用) 開始找 第一個yii\base\Module::layout 屬性不為空白的模組,使用該模組作為上下文模組, 並將它的yii\base\Module::layout 的值作為布局的值, 如果都沒有找到,表示不使用布局。
第二步,它決定第一步中布局的值和上下文模組對應到實際的布局檔案,布局的值可為:

路徑別名 (如 @app/views/layouts/main).
絕對路徑 (如 /main): 布局的值以斜杠開始,在應用的[[yii\base\Application::layoutPath|layout path] 配置路徑 中尋找實際的布局檔案,配置路徑預設為 @app/views/layouts。
相對路徑 (如 main): 在上下文模組的yii\base\Module::layoutPath配置路徑中尋找實際的布局檔案, 配置路徑預設為yii\base\Module::basePath模組目錄下的views/layouts 目錄。
布爾值 false: 不使用布局。
布局的值沒有包含副檔名,預設使用 .php作為副檔名。

嵌套布局

有時候你想嵌套一個布局到另一個,例如,在Web網站不同地方,想使用不同的布局, 同時這些布局共用相同的產生全域HTML5頁面結構的基本布局,可以在子布局中調用 yii\base\View::beginContent() 和yii\base\View::endContent() 方法,如下所示:

<?php $this->beginContent('@app/views/layouts/base.php'); ?>...child layout content here...<?php $this->endContent(); ?>

如上所示,子布局內容應在 yii\base\View::beginContent() 和 yii\base\View::endContent() 方法之間,傳給 yii\base\View::beginContent() 的參數指定父布局,父布局可為布局檔案或別名。

使用以上方式可多層嵌套布局。

使用資料區塊

資料區塊可以在一個地方指定視圖內容在另一個地方顯示,通常和布局一起使用, 例如,可在內容視圖中定義資料區塊在布局中顯示它。

調用 yii\base\View::beginBlock() 和 yii\base\View::endBlock() 來定義資料區塊, 使用 $view->blocks[$blockID] 訪問該資料區塊,其中 $blockID 為定義資料區塊時指定的唯一標識ID。

如下執行個體顯示如何在內容視圖中使用資料區塊讓布局使用。

首先,在內容視圖中定一個或多個資料區塊:

...<?php $this->beginBlock('block1'); ?>...content of block1...<?php $this->endBlock(); ?>...<?php $this->beginBlock('block3'); ?>...content of block3...<?php $this->endBlock(); ?>

然後,在布局視圖中,資料區塊可用的話會渲染資料區塊,如果資料未定義則顯示一些預設內容。

...<?php if (isset($this->blocks['block1'])): ?>  <?= $this->blocks['block1'] ?><?php else: ?>  ... default content for block1 ...<?php endif; ?>...<?php if (isset($this->blocks['block2'])): ?>  <?= $this->blocks['block2'] ?><?php else: ?>  ... default content for block2 ...<?php endif; ?>...<?php if (isset($this->blocks['block3'])): ?>  <?= $this->blocks['block3'] ?><?php else: ?>  ... default content for block3 ...<?php endif; ?>...

使用視圖組件

yii\base\View視圖組件提供許多視圖相關特性,可建立yii\base\View或它的子類執行個體來擷取視圖組件, 大多數情況下主要使用 view應用組件,可在應用配置中配置該組件, 如下所示:

[  // ...  'components' => [    'view' => [      'class' => 'app\components\View',    ],    // ...  ],]

視圖組件提供如下實用的視圖相關特性,每項詳情會在獨立章節中介紹:

  • 主題: 允許為你的Web網站開發和修改主題;
  • 片段快取: 允許你在Web頁面中緩衝片段;
  • 客戶指令碼處理: 支援CSS 和 JavaScript 註冊和渲染;
  • 資源套件處理: 支援 資源套件的註冊和渲染;
  • 模板引擎: 允許你使用其他模板引擎,如 Twig, Smarty。

開發Web頁面時,也可能頻繁使用以下實用的小特性。

設定頁面標題

每個Web頁面應有一個標題,正常情況下標題的標籤顯示在 布局中, 但是實際上標題大多由內容視圖而不是布局來決定,為解決這個問題, yii\web\View 提供 yii\web\View::title 標題屬性可讓標題資訊從內容視圖傳遞到布局中。

為利用這個特性,在每個內容視圖中設定頁面標題,如下所示:

<?php$this->title = 'My page title';?>然後在視圖中,確保在 <head> 段中有如下代碼:<title><?= Html::encode($this->title) ?></title>

註冊Meta元標籤

Web頁面通常需要產生各種元標籤提供給不同的瀏覽器,如<head>中的頁面標題,元標籤通常在布局中產生。

如果想在內容視圖中產生元標籤,可在內容視圖中調用yii\web\View::registerMetaTag()方法,如下所示:

<?php$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']);?>

以上代碼會在視圖組件中註冊一個 "keywords" 元標籤,在布局渲染後會渲染該註冊的元標籤, 然後,如下HTML代碼會插入到布局中調用yii\web\View::head()方法處:

<meta name="keywords" content="yii, framework, php">

注意如果多次調用 yii\web\View::registerMetaTag() 方法,它會註冊多個元標籤,註冊時不會檢查是否重複。

為確保每種元標籤只有一個,可在調用方法時指定鍵作為第二個參數, 例如,如下代碼註冊兩次 "description" 元標籤,但是只會渲染第二個。

$this->registerMetaTag(['name' => 'description', 'content' => 'This is my cool website made with Yii!'], 'description');$this->registerMetaTag(['name' => 'description', 'content' => 'This website is about funny raccoons.'], 'description');

註冊連結標籤

和 Meta標籤 類似,連結標籤有時很實用,如自訂網站表徵圖,指定Rss訂閱,或授權OpenID到其他伺服器。 可以和元標籤相似的方式調用yii\web\View::registerLinkTag(),例如,在內容視圖中註冊連結標籤如下所示:

$this->registerLinkTag([  'title' => 'Live News for Yii',  'rel' => 'alternate',  'type' => 'application/rss+xml',  'href' => 'http://www.yiiframework.com/rss.xml/',]);

上述代碼會轉換成

複製代碼 代碼如下:

<link title="Live News for Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">


和 yii\web\View::registerMetaTag() 類似, 調用yii\web\View::registerLinkTag() 指定鍵來避免產生重複的連結標籤。

視圖事件

yii\base\View 視圖組件會在視圖渲染過程中觸發幾個事件, 可以在內容發送給終端使用者前,響應這些事件來新增內容到視圖中或調整渲染結果。

  • yii\base\View::EVENT_BEFORE_RENDER: 在控制器渲染檔案開始時觸發, 該事件可設定 yii\base\ViewEvent::isValid 為 false 取消視圖渲染。
  • yii\base\View::EVENT_AFTER_RENDER: 在布局中調用 yii\base\View::beginPage() 時觸發, 該事件可擷取yii\base\ViewEvent::output的渲染結果,可修改該屬性來修改渲染結果。
  • yii\base\View::EVENT_BEGIN_PAGE: 在布局調用 yii\base\View::beginPage() 時觸發;
  • yii\base\View::EVENT_END_PAGE: 在布局調用 yii\base\View::endPage() 是觸發;
  • yii\web\View::EVENT_BEGIN_BODY: 在布局調用 yii\web\View::beginBody() 時觸發;
  • yii\web\View::EVENT_END_BODY: 在布局調用 yii\web\View::endBody() 時觸發。

例如,如下代碼將當前日期添加到頁面結尾處:

\Yii::$app->view->on(View::EVENT_END_BODY, function () {  echo date('Y-m-d');});

渲染靜態頁面

靜態頁面指的是大部分內容為靜態不需要控制器傳遞動態資料的Web頁面。

可將HTML代碼放置在視圖中,在控制器中使用以下代碼輸出靜態頁面:

public function actionAbout(){  return $this->render('about');}

如果Web網站包含很多靜態頁面,多次重複相似的代碼顯得很繁瑣, 為解決這個問題,可以使用一個在控制器中稱為 yii\web\ViewAction 的獨立操作。 例如:

namespace app\controllers;use yii\web\Controller;class SiteController extends Controller{  public function actions()  {    return [      'page' => [        'class' => 'yii\web\ViewAction',      ],    ];  }}

現在如果你在@app/views/site/pages目錄下建立名為 about 的視圖, 可通過如下rul顯示該視圖:

http://localhost/index.php?r=site/page&view=about
GET 中 view 參數告知 yii\web\ViewAction 操作請求哪個視圖,然後操作在 @app/views/site/pages目錄下尋找該視圖,可配置 yii\web\ViewAction::viewPrefix 修改搜尋視圖的目錄。

最佳實務

視圖負責將模型的資料展示使用者想要的格式,總之,視圖

  • 應主要包含展示代碼,如HTML, 和簡單的PHP代碼來控制、格式化和渲染資料;
  • 不應包含執行資料查詢代碼,這種代碼放在模型中;
  • 應避免直接存取請求資料,如 $_GET, $_POST,這種應在控制器中執行, 如果需要請求資料,應由控制器推送到視圖。
  • 可讀模數型屬性,但不應修改它們。
  • 為使模型更易於維護,避免建立太複雜或包含太多冗餘代碼的視圖,可遵循以下方法達到這個目標:
  • 使用 布局 來展示公用代碼(如,頁面頭部、尾部);
  • 將複雜的視圖分成幾個小視圖,可使用上面描述的渲染方法將這些小視圖渲染並組裝成大視圖;
  • 建立並使用 小組件 作為視圖的資料區塊;
  • 建立並使用助手類在視圖中轉換和格式化資料。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.