Yii2.0实用功能技巧解密之——布局文件多变量继承(嵌套、引用)终极功能

十度 Yii2 2015年11月30日 收藏

在做网站的过程中,大部分的页面结构都是相似的。如都有相同的头部和底部。各个页面这样仅仅是中间的部分不同。
Yii中的布局文件就是用来实现这样的功能。如:

布局文件:@app/views/layouts/main.php

  1. <!-- 前后的html 、head、body代码就省略了,只看最主要的部分 -->
  2. <header>
  3. </header>
  4. <div class="wrap">
  5.     <div class="container">
  6.         <!-- $content变量的值 就是子页面渲染之后的代码。也就是说子页面中的内容将输出到这个地方-->
  7.         <?= $content ?>
  8.     </div>
  9. </div>
  10. <footer class="footer">
  11. </footer>

后台action:

  1. public function actionIndex()
  2. {
  3.     $this->layout='@app/views/layouts/main.php';
  4.     return $this->render('index');
  5. }

执行顺序为:

  • 先想找index视图文件,
  • 渲染index视图文件 作为变量$output
  • 查找布局文件@app/views/layouts/main.php
  • 如果找到,则把$output值作为变量$content传递到布局文件
  • 把渲染后的布局文件作为结果返回
  • 如果没有找到布局文件,直接把$output作为结果返回


上面这个布局就是一列布局的页面,现在我们再增加另外一个布局:页面显示2列,左侧显示主要的内容,右侧显示统计信息。这个时候怎么办,再写一个和上面基本完全一样的代码吗?

布局文件嵌套(小部件:ContentDecorator)
这个小部件就是专为此功能而生的。
它的功能就是把begin和end之间的内容作为变量$content的值,然后渲染指定的视图文件。

两列布局文件:@app/views/layouts/column_2.php

  1. <!-- 先引用main.php布局文件, -->
  2. <?php $this->beginContent('@app/views/layouts/main.php');?>
  3. <div class="left_column">
  4.     <?= $content ?>
  5. </div>
  6. <div class="right_column">
  7. <!-- 在右侧共用的统一数据 -->
  8. </div>
  9. <?php $this->endContent();?>

把上面的action改为:

  1. public function actionIndex()
  2. {
  3.     $this->layout='@app/views/layouts/column_2.php';
  4.     return $this->render('index');
  5. }


执行顺序为:

  • 先把视图index渲染之后的结果作为变量$content传递到布局文件column_2中
  • 再把布局文件column_2中的beginContentendContent之间的内容作为变量$content传递到布局文件@app/views/layouts/main.php
  • 最后把main.php文件的结果输出。


注意:在上面布局文件column_2中,在beginContentendContent之外的内容是不会显示。

因此Yii中布局文件可以通过ContentDecorator小部件进行无限的嵌套。当然要小心点,不要弄成死循环了,如:ayout1引用layout2,layout2引用layout1文件


到现在你以为本文就结束了吗?终极技巧解密才刚刚开始!!!!!

多变量继承

先给你们看一个实例:

布局文件maiin:app/views/layouts/main.php

  1. <header>
  2. </header>
  3. <div class="wrap">
  4.     <div class="container">
  5.         <?= $content ?>
  6.     </div>
  7. </div>
  8. <footer class="footer">
  9.     <div>
  10.             <?= $footer ?>
  11.     </div>
  12. </footer>

可以看到,里面有两个变量:$content$footer

布局文件columns_2:@app/views/layouts/columns_2.php

  1. <?php AreaDecorator::begin(['viewFile'=>'@app/views/layouts/main.php'])?>
  2.         <?php Block::begin(['id' =>'content']);?>
  3.                 <div class="main_column">
  4.                         <?= $mainData ?>
  5.                 </div>
  6.                 <div class="side_column">
  7.                         <?= $sideData ?>
  8.                 </div>
  9.         <?php Block::end();?>
  10.         <?php Block::begin(['id' =>'footer']);?>
  11.                 <div>footer data </div>
  12.         <?php Block::end();?>
  13. <?php AreaDecorator::end();?>

布局文件columns_2引用main,并通过Blockid指定main里面的两个变量的内容

布局文件columns_3:@app/views/layouts/columns_3.php

  1. <?php AreaDecorator::begin(['viewFile'=>'@app/views/layouts/columns_2.php'])?>
  2.         <?php  Block::begin(['id' =>'mainData']);?>
  3.                 <div class="main_column_left">
  4.                         <div>main column left data</div>
  5.                 </div>
  6.                 <div class="main_column_right">
  7.                         <div><?= $content ?></div>
  8.                 </div>
  9.         <?php Block::end();?>
  10.         <?php Block::begin(['id' =>'sideData']);?>
  11.                 <div class="side_column">
  12.                         side data
  13.                 </div>
  14.         <?php Block::end();?>
  15. <?php AreaDecorator::end();?>

这个和上面的类似

action使用:

  1.     public function actionIndex()
  2.     {
  3.             $this->layout='@app/views/layouts/columns_3.php';
  4.         return $this->render('index');
  5.     }


在布局中可以定义多个点位符变量,然后在各个子布局中指定所使用的内容。

现在再也不用担心Yii布局里面只提供一个$content变量了

下面就是实现这个功能的小部件类
AreaDecorator小部件类:

  1. class AreaDecorator extends Widget
  2. {
  3.         public $viewFile;
  4.         
  5.         public $params = [];
  6.         public $ids=[];
  7.         
  8.         
  9.         public function init()
  10.         {
  11.                 if ($this->viewFile === null) {
  12.                         throw new InvalidConfigException('ContentDecorator::viewFile must be set.');
  13.                 }
  14.                 ob_start();
  15.                 ob_implicit_flush(false);
  16.         }
  17.         public function run()
  18.         {
  19.                 $params = $this->params;
  20.                 $params['content'] = ob_get_clean();
  21.                 
  22.                 $blocks = $this->view->blocks;
  23.                 if(count($this->ids)>0)
  24.                 {
  25.                         foreach ($blocks as $id=>$block)
  26.                         {
  27.                                 if(in_array($id,$this->ids))
  28.                                 {
  29.                                         $params[$id]=$block;
  30.                                         unset($this->view->blocks[$id]);
  31.                                 }
  32.                         }
  33.                 }
  34.                 else 
  35.                 {
  36.                         foreach ($blocks as $id=>$block)
  37.                         {
  38.                                 $params[$id]=$block;
  39.                                 unset($this->view->blocks[$id]);
  40.                         }
  41.                 }
  42.                 
  43.                 echo $this->view->renderFile($this->viewFile, $params);
  44.         }
  45. }