用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確認框,當你點擊**是**時才會真正跳轉過去