在做网站的过程中,大部分的页面结构都是相似的。如都有相同的头部和底部。各个页面这样仅仅是中间的部分不同。
Yii中的布局文件就是用来实现这样的功能。如:
布局文件:@app/views/layouts/main.php
- <!-- 前后的html 、head、body代码就省略了,只看最主要的部分 -->
- <header>
- </header>
- <div class="wrap">
- <div class="container">
- <!-- $content变量的值 就是子页面渲染之后的代码。也就是说子页面中的内容将输出到这个地方-->
- <?= $content ?>
- </div>
- </div>
- <footer class="footer">
- </footer>
后台action:
- public function actionIndex()
- {
- $this->layout='@app/views/layouts/main.php';
- return $this->render('index');
- }
执行顺序为:
上面这个布局就是一列布局的页面,现在我们再增加另外一个布局:页面显示2列,左侧显示主要的内容,右侧显示统计信息。这个时候怎么办,再写一个和上面基本完全一样的代码吗?
布局文件嵌套(小部件:ContentDecorator)
这个小部件就是专为此功能而生的。
它的功能就是把begin和end之间的内容作为变量$content的值,然后渲染指定的视图文件。
两列布局文件:@app/views/layouts/column_2.php
- <!-- 先引用main.php布局文件, -->
- <?php $this->beginContent('@app/views/layouts/main.php');?>
- <div class="left_column">
- <?= $content ?>
- </div>
- <div class="right_column">
- <!-- 在右侧共用的统一数据 -->
- </div>
- <?php $this->endContent();?>
把上面的action改为:
- public function actionIndex()
- {
- $this->layout='@app/views/layouts/column_2.php';
- return $this->render('index');
- }
执行顺序为:
注意:在上面布局文件column_2中,在beginContent和endContent之外的内容是不会显示。
因此Yii中布局文件可以通过ContentDecorator小部件进行无限的嵌套。当然要小心点,不要弄成死循环了,如:ayout1引用layout2,layout2引用layout1文件
到现在你以为本文就结束了吗?终极技巧解密才刚刚开始!!!!!
多变量继承
先给你们看一个实例:
布局文件maiin:app/views/layouts/main.php
- <header>
- </header>
- <div class="wrap">
- <div class="container">
- <?= $content ?>
- </div>
- </div>
- <footer class="footer">
- <div>
- <?= $footer ?>
- </div>
- </footer>
可以看到,里面有两个变量:$content和$footer。
布局文件columns_2:@app/views/layouts/columns_2.php
- <?php AreaDecorator::begin(['viewFile'=>'@app/views/layouts/main.php'])?>
- <?php Block::begin(['id' =>'content']);?>
- <div class="main_column">
- <?= $mainData ?>
- </div>
- <div class="side_column">
- <?= $sideData ?>
- </div>
- <?php Block::end();?>
- <?php Block::begin(['id' =>'footer']);?>
- <div>footer data </div>
- <?php Block::end();?>
- <?php AreaDecorator::end();?>
布局文件columns_2引用main,并通过Block的id指定main里面的两个变量的内容
布局文件columns_3:@app/views/layouts/columns_3.php
- <?php AreaDecorator::begin(['viewFile'=>'@app/views/layouts/columns_2.php'])?>
- <?php Block::begin(['id' =>'mainData']);?>
- <div class="main_column_left">
- <div>main column left data</div>
- </div>
- <div class="main_column_right">
- <div><?= $content ?></div>
- </div>
- <?php Block::end();?>
- <?php Block::begin(['id' =>'sideData']);?>
- <div class="side_column">
- side data
- </div>
- <?php Block::end();?>
- <?php AreaDecorator::end();?>
这个和上面的类似
action使用:
- public function actionIndex()
- {
- $this->layout='@app/views/layouts/columns_3.php';
- return $this->render('index');
- }
在布局中可以定义多个点位符变量,然后在各个子布局中指定所使用的内容。
现在再也不用担心Yii布局里面只提供一个$content变量了
下面就是实现这个功能的小部件类
AreaDecorator小部件类:
- class AreaDecorator extends Widget
- {
- public $viewFile;
- public $params = [];
- public $ids=[];
- public function init()
- {
- if ($this->viewFile === null) {
- throw new InvalidConfigException('ContentDecorator::viewFile must be set.');
- }
- ob_start();
- ob_implicit_flush(false);
- }
- public function run()
- {
- $params = $this->params;
- $params['content'] = ob_get_clean();
- $blocks = $this->view->blocks;
- if(count($this->ids)>0)
- {
- foreach ($blocks as $id=>$block)
- {
- if(in_array($id,$this->ids))
- {
- $params[$id]=$block;
- unset($this->view->blocks[$id]);
- }
- }
- }
- else
- {
- foreach ($blocks as $id=>$block)
- {
- $params[$id]=$block;
- unset($this->view->blocks[$id]);
- }
- }
- echo $this->view->renderFile($this->viewFile, $params);
- }
- }