GridView 是 Yii2 最強大的資料表格小部件,支援排序、分頁、篩選、欄位客製化、關聯資料顯示。
| 類別 | 用途 | 關鍵屬性 |
|---|---|---|
DataColumn | 一般資料欄(預設) | attribute, label, value, format, filter |
ActionColumn | 操作按鈕(檢視/編輯/刪除) | template, buttons, controller |
CheckboxColumn | 列選框(批次操作) | name, checkboxOptions |
SerialColumn | 自動序號 | header |
[
'label' => '自訂標題', // 覆蓋 attributeLabels()
'attribute' => 'id', // 對應模型屬性,支援排序
'value' => function ($model) { // 客製化顯示內容(閉包)
return $model->name . ' (' . $model->email . ')';
},
'format' => 'raw', // raw/html/ntext/date/email/url/image/boolean
'visible' => true, // 是否顯示
'headerOptions' => ['width' => '120'], // 表頭樣式
'contentOptions' => ['class' => 'text-center'],
]
// 控制器中
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => ['pageSize' => 15], // 預設 20
'sort' => ['attributes' => ['id', 'created_at']], // 僅允許這些欄位排序
]);
若使用 SearchModel,在 search() 方法中設定。
// Model 定義狀態常數與標籤映射
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
public static function getStatusLabels($key = null) {
$labels = ['' => '請選擇', self::STATUS_DELETED => '停用', self::STATUS_ACTIVE => '啟用'];
return $key === null ? $labels : ($labels[$key] ?? '未知');
}
// GridView 欄位配置
[
'attribute' => 'status',
'filter' => Html::activeDropDownList($searchModel, 'status', User::getStatusLabels(), ['class' => 'form-control']),
'value' => function ($model) { return User::getStatusLabels($model->status); },
]
| 方法 | 程式碼 | 適用場景 |
|---|---|---|
| 閉包格式化 | 'value' => fn($m) => date('Y-m-d', $m->created_at) | 簡單、一次性 |
| format 陣列 | 'format' => ['date', 'php:Y-m-d'], 'value' => 'created_at' | 統一格式、可復用 |
| 全域 formatter 元件 | config: 'formatter' => ['dateFormat' => 'yyyy-MM-dd'] → GridView: 'created_at:date' | 專案層級統一、最乾淨 |
[
'attribute' => 'id',
'value' => function ($model) {
return Html::a($model->id, ['user/view', 'id' => $model->id], ['class' => 'profile-link', 'target' => '_blank']);
},
'format' => 'raw', // 關鍵:不轉義 HTML
]
模型定義關聯:public function getOrder() { return $this->hasOne(Order::class, ['id' => 'order_id']); }
GridView 直接用 'order.customer_name' 顯示。
搜尋/排序需在 SearchModel 中:
// rules() 加入 'order.customer_name'
public function search($params) {
$query = self::find()->joinWith('order');
$dataProvider = new ActiveDataProvider(['query' => $query]);
$dataProvider->sort->attributes['order.customer_name'] = [
'asc' => ['order.customer_name' => SORT_ASC],
'desc' => ['order.customer_name' => SORT_DESC],
];
$query->andFilterWhere(['like', 'order.customer_name', $this->order_customer_name]);
// ...
}
[
'class' => 'yii\grid\ActionColumn',
'header' => '操作',
'headerOptions' => ['width' => '120'],
'template' => '{view} {update} {delete} {forbid}',
'buttons' => [
'forbid' => function ($url, $model) {
return Html::a('', ['user/forbid', 'id' => $model->id]);
},
],
]
composer require kartik-v/yii2-grid "@dev"
# 若報錯缺少 mpdf,暫時關閉導出功能:
// GridView::widget(['export' => false, ...])
# 或安裝:composer require kartik-v/yii2-mpdf "@dev"
'floatHeader' => true,捲動時表頭置頂。'mergeHeader' => true,節省垂直空間。'showPageSummary' => true,欄位設 'pageSummary' => true 或字串標籤。'responsive' => true, 'hover' => true。use kartik\grid\GridView;
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'responsive' => true,
'hover' => true,
'floatHeader' => true,
'showPageSummary' => true,
'panel' => [
'heading' => '用戶管理
',
'before' => '共 ' . $dataProvider->getTotalCount() . ' 筆',
'after' => false,
],
'toolbar' => [
'{export}',
'{toggleData}',
],
'toggleDataOptions' => [
'maxCount' => 200,
'confirmMsg' => '共 ' . number_format($dataProvider->getTotalCount()) . ' 筆,確定顯示全部?',
],
'export' => [
'fontAwesome' => 'fa fa-share-square-o',
'target' => '_blank',
'encoding' => 'UTF-8', // 或 GBK 視 Excel 版本
],
'exportConfig' => [
GridView::CSV => [
'label' => '導出 CSV',
'iconOptions' => ['class' => 'text-primary'],
'showHeader' => true,
'showPageSummary' => true,
'filename' => '用戶表_' . date('Y-m-d'),
'alertMsg' => '確定導出 CSV?',
'config' => ['colDelimiter' => ',', 'rowDelimiter' => "\r\n"],
],
GridView::EXCEL => [
'label' => '導出 Excel',
'config' => ['worksheet' => '用戶資料'],
],
],
'columns' => [
['class' => 'kartik\grid\SerialColumn'],
['class' => 'kartik\grid\CheckboxColumn', 'hiddenFromExport' => true],
[
'attribute' => 'username',
'mergeHeader' => true,
'pageSummary' => '總計',
],
[
'attribute' => 'email',
'mergeHeader' => true,
],
[
'attribute' => 'status',
'filter' => Html::activeDropDownList($searchModel, 'status', User::getStatusLabels(), ['class' => 'form-control']),
'value' => fn($m) => User::getStatusLabels($m->status),
'mergeHeader' => true,
],
[
'class' => 'kartik\grid\ActionColumn',
'template' => '{view} {update} {delete}',
'header' => '操作',
'mergeHeader' => true,
],
],
]);
合併表頭底框線變粗問題:
$this->registerCss(".kv-merged-header { border-bottom: 1px solid #eee !important; }");
| 問題 | 原因 | 解決 |
|---|---|---|
| 導出 CSV 中文亂碼 | Excel 預設非 UTF-8 | 用 encoding => 'GBK' 或 UTF-8 with BOM;或改導出 Excel 格式 |
| 關聯欄位無法排序 | 未在 dataProvider->sort 定義 | 補上 $dataProvider->sort->attributes['rel.field'] = [...] |
| mergeHeader 導致篩選輸入框消失 | CSS 衝突 | 調整 .kv-merged-header 樣式、確保 filter 輸入框可見 |
| floatHeader 在彈窗/側邊欄失效 | 容器 overflow 限制 | 確保 GridView 容器無 overflow:hidden,或設定 floatHeaderOffset |
Yii2 GridView 配合 kartik-v/yii2-grid 可滿足 95% 後台表格需求:固定表頭、合併篩選、多格式導出、總計列、編輯列。關鍵在於正確配置 DataProvider 排序、善用 mergeHeader 減少垂直佔用、處理導出編碼相容性。若專案需求極度複雜(如多層表頭、跨欄合併、即時協作),可考慮前端表格庫(AG Grid、Handsontable)配合 API 模式。