用gii生成的CRUD非常方便,index视图自带的数据列表也很强大,最右侧默认还带有 **查看详情**、**修改** 和 **删除** 三大功能按钮 但是这三个按钮不一定够用。例如我们做文章列表时,可能还会需要 **显示**(发布)、**隐藏**(作为草稿) 之类的按钮,这时候我们就需要自定义活动列了 ### 准备工作 首先我们跟着命名空间(yii\grid\ActionColumn)到 `vendor\yiisoft\yii2\grid` 下把 `ActionColumn.php` 拷贝出来,放到任意地方(例如我放在了自己新建的 app\column 下),我们要基于它进行修改 因为他是用于文章列表的活动列,所以我们可以给他改个名字,例如改为 **ArticleColumn.php**。不要忘记顺便修改命名空间及类名 ### 填写按钮名称 我们来看这个**ArticleColumn**的类属性`template`,它默认是这样的: ```php public $template = '{view} {update} {delete}'; ``` 也就是对应的**查看详情**、**修改** 和 **删除** 三大功能按钮 那么我想要添加一个**显示**按钮,我把它命名为`show`,于是将`template`的值改为 ```php public $template = '{view} {show} {update} {delete}'; ``` 表示把**显示按钮**放在了**查看详情按钮**后面 ### 生成按钮Html 然后看`initDefaultButtons`方法,我们可以发现每个按钮都是通过类似如下的代码生成的: ```php if (!isset($this->buttons['view'])) { $this->buttons['view'] = function ($url, $model, $key) { $options = array_merge([ 'title' => Yii::t('yii', 'View'), 'aria-label' => Yii::t('yii', 'View'), 'data-pjax' => '0', ], $this->buttonOptions); return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, $options); }; } ``` 根据这段代码我们可以判断出,`$this->buttons`数组的**键名**为上面提到的按钮英文名,**键值**为一个匿名回调函数,返回该按钮的html代码 --- 该匿名回调函数有三个参数: `$url`:Yii为你生成的url,一般为 **index.php?r=模块名/控制器名/按钮英文名&id=1** 。也就是说按钮英文名默认会被作为操作名来生成url,并且会附带上列表中当前这一行数据的主键作为参数传过去(如果你的数据表没有设置主键,则生成的url不带这个参数) `$model`:当前这一行数据的AR对象 `$key`:当前这一行数据的主键值。没有主键时此值为空 知道了这些,我们就可以开始来生成自己的 **显示按钮** 了 ```php if (!isset($this->buttons['show'])) { $this->buttons['show'] = function ($url, $model, $key) { $options = [ 'title' => '显示', 'aria-label' => '显示', 'data-pjax' => '0', ]; return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, $options); }; } ``` 好了,我们现在到Index视图层,把`GridView::widget`的参数数组中的`columns`键的值的最后一个成员改为 `['class' => 'app\column\ArticleColumn']` 保存,刷新页面即可看到效果 至于控制器里对应的`actionShow`方法就自己去实现吧 ### 进阶扩展 要是把 **显示** 和 **隐藏** 分开作为两个按钮,从用户体验的角度上肯定是不合理的 我们需要在匿名回调函数中做个判断,根据当前文章的状态,来显示相对的按钮 我在`actionShow`方法中添加一个参数`status`,通过向它传递0和1来控制文章的显示或隐藏 这时Yii生成的`$url`就不够用了,我们需要自己动手 最终的代码是这样的: ```php if (!isset($this->buttons['show'])) { $this->buttons['show'] = function ($url, $model, $key) { if($model->status){ // 如果当前文章状态为1(显示)时 $options = [ 'title' => '隐藏', 'aria-label' => '隐藏', 'data-pjax' => '0', ]; $url = Url::to(['show', 'id'=>$key, 'status`=>0); // 手动生成url return Html::a('<span class="glyphicon glyphicon-eye-close"></span>', $url, $options); } else { // 如果当前文章状态为0(隐藏)时 $options = [ 'title' => '显示', 'aria-label' => '显示', 'data-pjax' => '0', ]; $url = Url::to(['show', 'id'=>$key, 'status`=>1); return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, $options); } }; } ``` 很多时候为了防止误操作,PM还会要求先弹个窗让用户确认一下 Yii的前端库为此提供了一个很方便的属性`data-confirm` 具体使用方法就是在上面的`$options`数组中添加一个成员,例如: `'data-confirm' => '你真的要隐藏这篇文章吗?',` 如此一来,当你点击这个按钮时,就会先弹出一个confirm确认框,当你点击**是**时才会真正跳转过去