1. 程式人生 > >Yii2—檢視(View)

Yii2—檢視(View)

檢視(View)

檢視(View)這一部分比較多,總共包括11個知識點:

  • 基本定義
  • 部件(Widget)
  • 安全
  • 模板引擎
  • 在模板中使用檢視物件
    • 設定頁面標題
    • 新增meta標籤
    • 註冊連線標籤
    • 註冊CSS
    • 註冊指令碼
    • 註冊asset bundles
  • 佈局(Layout)
  • 區域性(Partial)
  • 訪問上下文
  • 靜態頁面
  • 快取區塊
  • 自定義檢視元件
1、基本定義
檢視基本上就是我們所說的在views資料夾中的顯示前臺頁面的模板。另外還有一個對應的檢視類(yii\web\view)這個是在Yii2中新增加的,我們在views中的模板檔案中看到的$this物件就是Yii2中的檢視物件。 我們下面就用模板來稱呼前臺view中的檢視,以便和yii\web\view這個檢視類混淆。
預設情況下,Yii使用php語言來解析模板,也就是說在views中的模板裡面直接用php程式碼來輸出資料。
在模板頁面最好不要包含複雜的php邏輯程式碼,應該儘可能的把它們放到控制器或者部件裡面去實現。
模板一般在控制器中的動作(Action)裡執行render()
方法的時候呼叫。
  1. public function actionIndex()
  2. {
  3.     return $this->render('index', ['username' => 'samdark']);
  4. }
render()的第一個引數是要使用的模板的名稱。
在這裡只需要新增模板的檔名就可以了,不用加路徑以及字尾。Yii會在當前控制器的ID(如site)目錄下搜尋這個模板檔案。
如當前控制器是SiteController,那個將會在views/site目錄下面搜尋index檔案。
如果想知道Yii是怎樣查詢檢視檔案的可以檢視yii\base\Controller::render()
第二個引數是一個name-value的陣列。這個陣列會直接傳遞到views目錄中的模板檔案裡面,並且name可直接作為php變數來引用,value就是對應的變數的值。如上面的index檢視檔案為views/site/index.php
  1. <p>Hello, <?= $username ?>!</p>
任意型別的資料都可以傳遞到view檢視中,包含陣列和物件。
除了上面說的render()方法外,在yii\web\Controller中還有幾種載入檢視的方法:
  • render():渲染一個模板,然後對渲染的結果應用佈局檔案。這個是通常用來渲染一個完整的頁面。
  • renderPartial():僅僅渲染一個模板,不對渲染的結果使用佈局檔案。通常用來渲染頁面的區域性。
  • renderAjax():也是隻渲染模板,不使用佈局檔案,但會載入所有註冊的js/css等指令碼檔案。通常把渲染的html程式碼作為Ajax請求的響應。
  • renderFile()渲染一個模板檔案,基本和renderPartial()功能一樣,只不過這裡要求的是檔案的路徑而不是檔案的名稱。
2、部件(Widget)
部件是檢視中的獨立的區塊,用來把一些複雜的邏輯、頁面顯示及相應的功能實到一個獨立的元件中。
Yii內建很多常用的部件,如表單(active form),麵包屑(breadcrumbs),選單(menu)以及對bootstrap的包裝。另外在某些擴充套件元件中也提供了部件,如官方的jQueryUI元件。
下面是在檢視檔案中使用部件的例子:
  1. // Note that you have to "echo" the result to display it
  2. //輸出部件Menu中的內容
  3. echo \yii\widgets\Menu::widget(['items' => $items]);
  4. // Passing an array to initialize the object properties
  5. //可往部件中傳遞引數來初始化部件
  6. $form = \yii\widgets\ActiveForm::begin([
  7.     'options' => ['class' => 'form-horizontal'],
  8.     'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']],
  9. ]);
  10. ... form inputs here ...
  11. \yii\widgets\ActiveForm::end();
在第一個例子中僅僅只呼叫widget()方法來輸出內容。第二個例子中begin()end()方法之間的內容,將會在呼叫end()方法的時候一起輸出。

3、安全
最主要的安全規則之一就是對所有的輸出進行編碼,如果違反這一規則將會導致指令碼執行漏洞,最大可能會導致XSS跨域站點攻擊以到管理員密碼。
Yii提供了一系列的工具來幫助你實現對輸出的編碼。最基本的過濾標籤的程式碼如下:
  1. <?php
  2. use yii\helpers\Html;
  3. ?>
  4. <div class="username">
  5.     <?= Html::encode($user->name) ?>
  6. </div>
但如果想渲染檢視的時候就會有點麻煩,所以我們提供了另外一個類來完成這項任務yii\helpers\HtmlPurifier:
  1. <?php
  2. use yii\helpers\HtmlPurifier;
  3. ?>
  4. <div class="post">
  5.     <?= HtmlPurifier::process($post->text) ?>
  6. </div>
HTMLPurifier 內部已經把所有的安全都考慮好了,所以輸出的結果是完全安全的,然而它的執行效率卻不高,所以應該考慮使用快取(caching result).

4、模板引擎
我們還提供了2個官方的模板引擎SmartyTwig,想了解更多情況可以檢視這裡使用模板引擎(Using template engines )

5、在模板中使用檢視物件
yii\web\View元件的物件可以在模板裡面直接使用,即模板檢視中的$this變數。有了這個變數可以進行更多的操作,如設定頁面的標題、meta資訊、指令碼和訪問當前的上下文物件。
1、設定頁面標題
  1. $this->title = 'My page title';
2、新增meta標籤
meta標籤如encoding、keywords、description等
  1. $this->registerMetaTag(['encoding' => 'utf-8']);
上面的引數中的陣列為<meta>標籤中對應的名稱和值。生成如下Html程式碼
  1. <meta encoding="utf-8">
有時候某種型別的標籤只需要一個,這個時候就需要第二個引數。
  1. $this->registerMetaTag(['name' => 'description', 'content' => 'This is my cool website made with Yii!'], 'meta-description');
  2. $this->registerMetaTag(['name' => 'description', 'content' => 'This website is about funny raccoons.'], 'meta-description');
如果對同一個型別(這個例子裡面為meta-description)的registerMetaTag呼叫多次,後面的值將會覆蓋前面的值,最終只有最後的一個標籤會渲染出來。
  1. <meta name="description" content="This website is about funny raccoons.">
3、註冊連線標籤
<link>標籤在很多情況下都很有用,如自定義favicon、RSS等等
  1. $this->registerLinkTag([
  2.     'title' => 'Lives News for Yii Framework',
  3.     'rel' => 'alternate',
  4.     'type' => 'application/rss+xml',
  5.     'href' => 'http://www.yiiframework.com/rss.xml/',
  6. ]);
輸出Html如下
  1. <link title="Lives News for Yii Framework" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/" />
meta標籤一樣,也可以指定第二個型別引數,從而只生成一個<link>標籤。

4、註冊CSS
還可以用檢視物件中的registerCss()registerCssFile()來註冊CSS。registerCss()方法用來註冊CSS程式碼段,registerCssFile()用來註冊一個外部CSS檔案。
  1. $this->registerCss("body { background: #f00; }");
上面的程式碼將會在頭部新增如下程式碼
  1. <style>
  2. body { background: #f00; }
  3. </style>
如果想設定style的一些額外的屬性,可以給第三個引數傳遞name-value陣列。如果想和上面一樣只顯示一條style標籤,可以象上面那樣設定第四個引數。
  1. $this->registerCssFile("http://example.com/css/themes/black-and-white.css", [BootstrapAsset::className()], ['media' => 'print'], 'css-print-theme');
上面的程式碼將新增一個css檔案到頁面的頭部中。
  • 第一個引數指定要新增的css檔案
  • 第二個引數指定這個css檔案依賴的BootstrapAsset。意思是說在BootstrapAsset裡面的css檔案載入完成之後才載入剛才指定的css檔案。如果沒有指定依賴項那麼這個css檔案和BootstrapAsset裡面的css檔案的將沒有先後順序。
  • 第三個引數設定<link>標籤的其它屬性的值。
  • 最後一個引數用來唯一標識這個css檔案。如果沒有指定的話將會用這個css的URL連線。
在註冊外部css檔案的時候,我們推薦你使用asset bundles 而不是使用registerCssFile()。使用asset bundles的話可以合併和壓縮多個css檔案,以減少網路流量的傳輸。

5、註冊指令碼
利用yii\web\View 還可以註冊指令碼檔案。註冊指令碼也有2個方法,registerJs()用來註冊內部js程式碼,registerJsFile()用來註冊外部Js檔案。內部js程式碼可用於配置或者動態生成程式碼的時候,
  1. $this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
第一個引數是我們要新增到頁面的js程式碼,
第二個引數指定js指令碼新增到頁面的位置。
  1. View::POS_HEAD 在頭部新增
  2. View::POS_BEGIN 在[color=Red]<body>[/color]標籤開始之後
  3. View::POS_END 在[color=Red]</body>[/color]標籤結束之前
  4. View::POS_READY 在document [color=Red]ready[/color] event 準備好之後,這個會自動註冊並使用jQuery。
  5. View::POS_LOAD  在 document [color=Red]load[/color] event 準備好之後, 這個會自動註冊並使用jQuery。
最後的一個引數是js程式碼的唯一標識,如果註冊有相同的唯一標識的js則後面的會替換前面的js程式碼。如果沒有設定標識,js程式碼本身將被作為這個id.

外部Js程式碼新增如下
  1. $this->registerJsFile('http://example.com/js/main.js', [JqueryAsset::className()]);
registerJsFile()的引數和registerCssFile()的引數一樣,在上面的例子中註冊的main.js檔案依賴項JqueryAsset。也就是說main.js將會在jquery.js檔案載入完成之後才載入。如果沒有定義依賴項,則main.js和jquery.js將沒有先後順序。

registerCssFile()一樣,我們也建議你使用asset bundles來註冊外部js檔案而不是使用registerJsFile()

6、註冊asset bundles
如先前所提到的,在頁面中最好使用asset bundles,而不是直接在頁面中使用css和javascript。關於asset bundles的相關資訊可以檢視asset manager

使用已經定義的asset bundles程式碼如下
  1. \frontend\assets\AppAsset::register($this);
6、佈局(Layout)
在一個應用中如果大部分的頁面顯示的內容基本相同,那麼使用全域性佈局檔案無疑是最好的選擇。
佈局檔案中一般包括頭部、尾部、主選單以及其它在所有頁面公共的部分。下面這個是最基本的一個佈局檔案。
  1. <?php
  2. use yii\helpers\Html;
  3. ?>
  4. <?php $this->beginPage() ?>
  5. <!DOCTYPE html>
  6. <html lang="<?= Yii::$app->language ?>">
  7. <head>
  8.     <meta charset="<?= Yii::$app->charset ?>"/>
  9.     <title><?= Html::encode($this->title) ?></title>
  10.     <?php $this->head() ?>
  11. </head>
  12. <body>
  13. <?php $this->beginBody() ?>
  14.     <div class="container">
  15.         <?= $content ?>
  16.     </div>
  17.     <footer class="footer"> 2013 me :)</footer>
  18. <?php $this->endBody() ?>
  19. </body>
  20. </html>
  21. <?php $this->endPage() ?>
在上面的程式碼中$content是一個變數,它的值就是檢視檔案渲染之後的結果。
在程式碼的開始,我們使用php的方法use來引入Html幫助類。這個類主要功能就是用於對輸出的結果進行編碼。
另外還有一些特殊的方法如beginPage()/endPage(), head(), beginBody()/endBody() 這些在渲染頁面的時候都觸發相應的事件。你可以在這些事件裡面註冊指令碼、連線以及處理頁面等等。

7、區域性檢視(Partial)
有時候一些Html程式碼需要在多個檢視頁面使用,大多部情況下這些Html程式碼太簡單了以至於建立部件(Widget)有點浪費。
區域性檢視也是檢視檔案,它也存在於views目錄下面並且檔名以“_”開頭。例如我們要顯示所有使用者資訊的列表,同時還在其它地方顯示一個單獨使用者的資訊。
首先定義使用者資訊的區域性檔案_profile.php
  1. <?php
  2. use yii\helpers\Html;
  3. ?>
  4. <div class="profile">
  5.     <h2><?= Html::encode($username) ?></h2>
  6.     <p><?= Html::encode($tagline) ?></p>
  7. </div>
index.php檔案中顯示所有使用者的列表資訊
  1. <div class="user-index">
  2.     <?php
  3.     foreach ($users as $user) {
  4.         echo $this->render('_profile', [
  5.             'username' => $user->name,
  6.             'tagline' => $user->tagline,
  7.         ]);
  8.     }
  9.     ?>
  10. </div>
同樣,在其它的檢視檔案可以重複使用這個區域性檢視來顯示一個使用者的資訊
  1. echo $this->render('_profile', [
  2.     'username' => $user->name,
  3.     'tagline' => $user->tagline,
  4. ]);
在當前的檢視頁面中呼叫render()來渲染區域性檢視時候可以有多種不同的方式來指定區域性檢視檔案。最常用的一種是像上面例子那樣直接指定區域性檢視的檔名稱。當然這個區域性檢視檔案要和這個檢視檔案處於同一個目錄下。如果區域性檢視檔案是在子目錄下面,那麼就需要指定子目錄的名稱,如public/_profile
另外也可以在路徑中使用別名,如@app/views/common/_profile
除了另外還可以使用絕對路徑加上檢視的名稱如/user/_profile //user/_profile。絕對路徑要以“/”或者"//"開頭。如果以“/”開頭將會從當前模組的view路徑裡面查詢,如果以"//"開頭,前者會從應用程式的view路徑中查詢

8、訪問上下文
檢視檔案一般由控制器或者部件來呼叫,在這兩種情況下我們都可以通過檢視物件的$this->context來得到相應的控制器或者部件。例如想在當前的檢視中得到路由資訊可以用
  1. echo $this->context->getRoute();

9、靜態頁面
如果需要渲染一個靜態頁面可以使用ViewAction類。它會根據使用者的設定呼叫這個action來顯示相應的檢視檔案。
首先在控制器裡面的actions裡面
  1. class SiteController extends Controller
  2. {
  3.     public function actions()
  4.     {
  5.         return [
  6.             'static' => [
  7.                 'class' => '\yii\web\ViewAction',
  8.             ],
  9.         ];
  10.     }
  11.     //...
  12. }
@app/views/site/pages/目錄中建立index.php
  1. //index.php
  2. <h1>Hello, I am a static page!</h1>
現在可以通過/index.php?r=site/static來訪問
預設情況下是通過GET引數中的view變數來顯示相應的靜態檔案的。如果URL為/index.php?r=site/static?&view=about那麼將會顯示@app/views/site/pages/about.php靜態檔案。
靜態檔案預設按照如下順序來顯示
  • 獲取GET引數:view
  • 如果沒有指定view引數,將使用預設的index.php靜態檔案。
  • 在靜態檔案的目錄中查詢相應的檔案(viewPrefix):pages為目錄
  • 使用相應的佈局檔案。
更多相關資訊可以檢視yii\web\ViewAction

10、快取區塊
關於對區塊的快取可以檢視快取章節

11、自定義檢視元件

由於view也是一個應用程式元件,所以你可以替換為你自己自定義的元件。自定義的檢視元件一般從yii\base\View或者yii\web\View繼承。可以在應用程式的配置檔案(如config/web.php)中進行設定:
  1. return [
  2.     // ...
  3.     'components' => [
  4.         'view' => [
  5.             'class' => 'app\components\View',
  6.         ],
  7.         // ...
  8.     ],
  9. ];