Yii2 GridView 刪除按鈕預設使用瀏覽器原生 confirm(),樣式無法自訂,且為同步阻塞。引入 kartik-v/yii2-dialog(基於 Bootstrap3 Dialog)可快速獲得美觀、非同步的對話框。
composer require kartik-v/yii2-dialog @dev
基本用法:
use kartik\dialog\Dialog;
// Alert
Dialog::alert('訊息內容');
// Confirm(非同步,需回調)
Dialog::confirm('確定刪除?', function($result) {
if ($result) { /* 確定邏輯 */ }
});
// Dialog
Dialog::widget(['title' => '標題', 'content' => '內容'])
vendor/yiisoft/yii2/assets/yii.js 中的 yii.confirm 可被覆寫。
yii.confirm = function (message, ok, cancel) {
krajeeDialog.confirm(message, function (data) {
if (data) { !ok || ok(); }
else { !cancel || cancel(); }
});
return false; // 取消預設點擊行為,交由回調處理
};
class AppAsset extends AssetBundle {
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = ['css/site.css'];
public $js = ['js/confirm.js']; // 關鍵
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}
原生 confirm() 同步回傳 true/false,程式碼可寫成:
if (confirm('刪除?')) { doDelete(); }
但 krajeeDialog.confirm 為**非同步回調**,不能這樣寫:
// 錯誤寫法:永遠不會進入 if
if (krajeeDialog.confirm('刪除?', function(r){ return r; })) { doDelete(); }
正確寫法:將後續邏輯放入回調
krajeeDialog.confirm('刪除?', function (result) {
if (result) { doDelete(); }
});
修改 vendor/kartik-v/yii2-grid/GridView.php 中 getToggleDataScript() 回傳的 JS:
$url = Url::current([$this->_toggleDataKey => $tag]);
return "$('#{$this->_toggleButtonId}').on('{$event}',function(e){
e.preventDefault();
krajeeDialog.confirm('{$msg}',function(data){
if (data) { window.location.href='{$url}'; }
});
});";
涉及 kv-grid-export.js 的 kvConfirm、notify、listenClick,建議重寫整個 JS 模組或改用自訂按鈕。
public function actionCreate() {
$model = new User();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
Yii::$app->session->setFlash('success', '建立成功');
return $this->redirect(['index']);
}
return $this->render('create', ['model' => $model]);
}
<?= \kartik\alert\Alert::widget() ?>
// 或加入自動淡出 JS
$this->registerJs("$('.alert-success').animate({opacity:1},5000).fadeOut('slow');");
<?php
namespace common\widgets;
class Popup extends \yii\bootstrap\Widget {
public $popupTypes = [
'default' => 'BootstrapDialog.TYPE_DEFAULT',
'info' => 'BootstrapDialog.TYPE_INFO',
'primary' => 'BootstrapDialog.TYPE_PRIMARY',
'success' => 'BootstrapDialog.TYPE_SUCCESS',
'warning' => 'BootstrapDialog.TYPE_WARNING',
'danger' => 'BootstrapDialog.TYPE_DANGER',
];
public $sizeTypes = [
'normal' => 'BootstrapDialog.SIZE_NORMAL',
'small' => 'BootstrapDialog.SIZE_SMALL',
'wide' => 'BootstrapDialog.SIZE_WIDE',
'large' => 'BootstrapDialog.SIZE_LARGE',
];
public $title;
public $size;
public function init() {
parent::init();
$this->title = $this->title ?: '訊息提示';
$this->size = ($this->size && isset($this->sizeTypes[$this->size])) ? $this->size : 'small';
$session = Yii::$app->session;
$flashes = $session->getAllFlashes();
$view = $this->getView();
foreach ($flashes as $type => $data) {
if (!isset($this->popupTypes[$type])) continue;
$data = (array) $data;
foreach ($data as $message) {
$view->registerJs("
var dialogShow = BootstrapDialog.show({
type: {$this->popupTypes[$type]},
title: '{$this->title}',
message: '" . addslashes($message) . "',
size: {$this->sizeTypes[$this->size]},
buttons: [{
label: '關閉',
action: function(dialogItself) { dialogItself.close(); }
}]
});
");
if ($type === 'success') {
$view->registerJs("setTimeout(function(){ dialogShow.close(); }, 3000);");
}
}
$session->removeFlash($type); // 避免重複顯示
}
}
}
use common\widgets\Popup;
<?= Popup::widget(['title' => '提示', 'size' => 'small']) ?>
kartik-v/yii2-dialog 即刻擁有美觀、非同步對話框。yii.confirm 讓 GridView 刪除按鈕自動套用新樣式。Popup 元件複用性高,成功訊息可自動關閉。