一篇为你讲透Yii2的widget这货

yii开发中,用到了大量的widget,咱们也能本身创建一个widget,今天为你讲解widget的运行机理,让你游刃有余的操做它。php

ActiveForm、Breadcrumbs、DetailView、LinkPager、ListView 等等,这些内置的挂件让咱们开发变的如此简单。数组

本节教你自定义一个widget,顺便说下widget的运行机理和几大重要函数。浏览器

老规矩,先说目录。app

  • 何时用widgetyii

  • 新建一个widget编辑器

  • begin & end 方法函数

  • beforeRun & afterRun 方法布局

begin...this

何时用widget

场景仍是蛮简单的、当咱们发现页面有的区块重复出现了,好比TOP十、好比内容编辑器等、就要考虑是否要作成一个widget了。spa

新建一个widget

咱们仍是举例把,新建一个Top10的区块。首先咱们要在应用程序的components下新建一个Top10Widget的类,根据psr-4规则,布局应该是这样的

  • components

  • componentsTop10Widget.php

Top10Widget.php的内容

namespace app\components;

use yii\base\Widget;
class Top10Widget extends Widget {
    public $catId;
    
    public function init(){
        parent::init();
        if(empty($this->catId)){
            $this->catId = 0;
        }
    }
    
    public function run(){        
        parent::run();
    }
}

做为一个widget,你必需要继承于yiibaseWidget才能够,就像咱们的Top10Widget同样。类的变量表明未来视图使用该挂件时对其传递的参数,除此以外咱们要重载Widget的init和run两个方法。

要注意的一点是,在方法里须要先调用父类的对应方法,如上面代码同样,这个要记住。

init() 方法旨在对传递过来的变量进行验证、筛选及处理,因此对于init而言,若是参数出现异常表明前台并无传递参数正确,这个时候你可使用throw new Exception("xxx");来抛出异常,页面会报错,固然为了美观,咱们可使用try ... catch....将这个异常接住而后更友好的显示。

小提示:对于throw异常的方法,在run中也同样,我建议try .... catch ....它们。

偷偷的小广告 北哥工兵连 每1-2天一篇干货 http://nai8.me

好的,上面说了init的初衷,接下来讲下run函数(有些挂件并无使用init,而是将全部数据都放到run里处理也是能够的,不过我通常不这么干)。

run() 方法表明该关键的执行逻辑,针对于init处理过的变量,进行逻辑处理,最后显示给客户想要的东西。就和action同样,这里面能够执行不少不少。

最后咱们能够经过return 或 echo 将结果返回给浏览器

namespace app\components;

use yii\base\Widget;
class Top10Widget extends Widget {
    public $catId;
    
    // 省略的代码....
    
    public function run(){        
        parent::run();
        return $this->catId; // 不彻底等价于 echo $this>-catId
    }
}

那么一个问题出现了,若是我仅仅是想像是一些数字结果,而是但愿它的样子更丰富,我要如何作那?
我想你也想到了,咱们能够对这个挂件加载一个视图,而后在视图里处理。

namespace app\components;

use yii\base\Widget;
class Top10Widget extends Widget {
    public $catId;
    
    // 省略的代码....
    
    public function run(){        
        parent::run();
        return $this->render('top10',[
            'catId'=>$this->catId
        ]);
    }
}

top10.php文件在哪创建?按照约定,咱们须要在appcomponentsviews下创建这个视图。

use app\components\Top10Widget;
<?= Top10Widget::widget(['catId'=>98]);?>

看到了吧,和控制的视图同样,先use,在使用。

到这里我想你们经过yii的手册都已经知道了,新建一个widget是如此简单。

从上面咱们知道,咱们经过使用Top10Widget::widget()方法将参数传递给挂件并处理,可是有的时候可能数组不少,用传参方法不太适合,那么咱们要如何去作那?见下段。

begin & end 方法

咱们可使用begin和end方法将要传递的内容总体传递给挂件作处理。
以下视图

<?php
use app\components\Top10Widget;
?>

<?php Top10Widget::begin();?>
<b>hello widget</b>
<?php Top10Widget::end();?>

在挂件里,咱们以下处理

namespace app\components;

use yii\base\Widget;
class Top10Widget extends Widget {
    public $catId;
    
    public function init(){
        parent::init();
        ob_start();
    }
    
    public function run(){        
        parent::run();
        $content = ob_get_clean();
        return "<div style='color:red'>{$content}</div>";
    }
}

经过 ob_start和ob_get_clean方法,咱们得到关键包围的内容,更多关于缓冲区的内容能够看php文档 http://php.net/manual/zh/ref....

到此为止,我想你对挂件的创建已经没有任何惧怕了,它们如此简单,各类状况也都有对策。可是若是你是一个技术发烧友,你必定发现yiibaseWidget下还有两个函数beforeRun和afterRun,彷佛他们在run函数先后进行了什么?接下来给你说说它们俩。

beforeRun & afterRun 方法

若是用一句话归纳就是咱们能够经过beforeRun的返回值是真是假来决定挂件是否执行run函数,而afterRun则能对run的处理结果再一次处理后返给浏览器,看下widget实现源码就知道了

public static function widget($config = [])
{
    ob_start();
    ob_implicit_flush(false);
    try {
        /* @var $widget Widget */
        $config['class'] = get_called_class();
        $widget = Yii::createObject($config);
        $out = '';
        if ($widget->beforeRun()) {
            $result = $widget->run();
            $out = $widget->afterRun($result);
        }
    } catch (\Exception $e) {
        // close the output buffer opened above if it has not been closed already
        if (ob_get_level() > 0) {
            ob_end_clean();
        }
        throw $e;
    }

    return ob_get_clean() . $out;
}

你必定看到了这段代码

if ($widget->beforeRun()) {
    $result = $widget->run();
    $out = $widget->afterRun($result);
}

聪明的你明白了,换句话说,咱们能够在自定义widget时候经过重载beforeRun来进一步控制run是否处理,进而让咱们的挂件更加灵活。

那么回过头来咱们思考,为什么要插入这样一个beforeRun开关函数那,缘由在于init函数并无返回值,它控制不了run是否执行,而run函数的功能是接收数据进行数据处理,所以在它以前加一个函数来进行再一次判断决定是否往下走是有必要的。

此篇讲完,但愿对你有用。

相关文章
相关标签/搜索