Yii2的相關學習記錄,alert等美化、confirm異步、session中的flash及小部件的使用(六)


呃,系統自帶的alert、confirm等彈出框實在是難看,作為一個顏控,這能忍?

這里我用的是kartik-v/yii2-dialog,這個是基於bootstrap3-dialog這個來做了一些常用alert、confirm和dialog的小部件封裝,當然了,本質上還是bootstrap3-dialog,可以用原生的方法,原生方法的用法點這里,而bootstrap3-dialog又是基於bootstrap3的modals做的封裝。嗯,基本關系就是這樣。在搜索這個相關知識時,經常會看到有人提到bootbox,這個同樣是流行的一個美化插件,基本原理類似,用法稍微不同,在packagist搜索yii2 bootbox會發現也有人為Yii2做了集成(或者自己集成也行,后面會講到),同樣值得推薦。

按照說明安裝,最好是按照github的說明,因為最新的一般都會在這里先更新。composer中要用@dev。可以看這里的說明,如果不成功,先composer self-update,再試下,當初安裝時也是各種報錯不行,后來突然就好了。稍微注意的是confirm,dialog調用時要求必須寫回調,否則就報錯。

還是蠻漂亮的。但是像是Yii框架Gridview自帶的confirm(像是刪除按鈕),點擊時還是原生的,因為它的源碼就是用的confirm命令,好在Yii框架提供了方法,可以讓我們覆蓋confirm方法。具體可如下操作:

1、我們可以先看下在vendor/yiisoft/yii2/assets/yii.js文件中的confirm方法:注釋中就可以看到,可以用yii.confirm來重寫此設置。

 /**
    * Displays a confirmation dialog.
    * The default implementation simply displays a js confirmation dialog.
    * You may override this by setting `yii.confirm`.
    * @param message the confirmation message.
    * @param ok a callback to be called when the user confirms the message
    * @param cancel a callback to be called when the user cancels the confirmation
    */
    confirm: function (message, ok, cancel) {
        if (confirm(message)) {
            !ok || ok();
        } else {
            !cancel || cancel();
        }
    },

2、那我們就重寫,可以在backend/web/js中新建confirm.js文件,然后重新,可參照此文章,這是設置bootbox的,而且版本有點過時,不過下方的評論有最新方法。而我們的設置與此原理是一致的,只不過是改成kartik-v/yii2-dialog所需求的參數樣式:

yii.confirm = function (message, ok, cancel) {
    krajeeDialog.confirm(message,function(data){
        if (data) {
            !ok || ok();
        } else {
            !cancel || cancel();
        }
    });
    // confirm will always return false on the first call
    // to cancel click handler
    return false;
}

3、我們需要注冊此js,可以在backend/assets/Appasset.php中添加上方的js文件:

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',
    ];
}

這樣一來,在點擊刪除按鈕便會發現可以調用了:

由於我們用的是kartik-GridView,它的兩個功能展示全部記錄和導出csv等的提示,都是用的原生的confirm,強迫症的我們能忍嗎?好吧,我忍了,這里只給出改的思路,尤其是只懂基礎js的我來說,先把時間放在其它地方吧。(2017.03.31注:3.1.2版本以上的kartik-GridView中會自動帶有yii2-dialog來提示,所以下面修改js什么的沒什么用了。)

在改之前,首先我們需要明確kartik-v/yii2-dialog的confirm(bootbox同樣)和原生confirm的不同。原生confirm是同步的,而kartik-v/yii2-dialog的confirm方法是異步回調的。這導致原生的confirm可以直接這樣寫:

function abc(){
    return window.confirm('123');//confirm點擊確認返回true,取消返回false,不點擊就等着用戶點擊    
}
if(abc()){
    alert('456');//點擊是,會彈出alert彈窗
}

而如果你用kartik-v/yii2-dialog的confirm也這樣寫,則永遠不會彈窗,因為是異步回調的,不會去等你點擊。

function abc(){
    krajeeDialog.confirm('123',function(result){
        if(result){
            return true;
        }else{
            return false;
        }
    });
}
if(abc()){
    alert('456');//由於是異步回調,所以不管點不點都不會彈窗
}

可能有人會想(比如我)這樣寫行不行?不行,不支持這樣的寫法,bootstrap3-dialog中這樣寫返回的是窗口有沒有open。

if(krajeeDialog.confirm('123',function(result){}){
    return true;
}else{
    return false;      
}

所以要想在kartik-v/yii2-dialog的confirm中執行alert,只能將alert放在回調函數中:

function abc(){
    krajeeDialog.confirm('123',function(result){
        if(result){
            alert('456');
        }else{
           //do something
        }
    });
}

 以上的不同,再加上是在vendor中修改有違原則啊(拿出來很費勁,又是繼承什么的,而導出csv的js沒找到類似yii.js那樣覆蓋的方法,只能重新寫引入什么的),也是我不想改源碼的原因。坑爹。好吧,下面繼續說怎么改:

1、{toggleData}顯示全部記錄,它的調用confirm是在vendor/kartik-v/yii2-grid/GridView.php中的getToggleDataScript方法,我們修改return就可以:

$url=Url::current([$this->_toggleDataKey => $tag]);//先定義需要跳轉的url
return "\$('#{$this->_toggleButtonId}').on('{$event}',function(e){
    e.preventDefault();//先阻止點擊事件
    krajeeDialog.confirm('{$msg}',function(data){
        if (data) {
            window.location.href='{$url}';//點擊是則跳轉
        }
    });
    //下面這條是原來的方法
    // if(!window.confirm('{$msg}')){e.preventDefault();}
});";

2、{export}中的導出提示,是在vendor/kartik-v/yii2-grid/assets/js/kv-grid-export.js中:這個就麻煩了,感覺需要重寫關聯的notify方法和listenClick方法。誰寫完了,麻煩告訴一聲吧。

kvConfirm: function (msg) {             
    try {
        return window.confirm(msg);//調的這個
    }
    catch (err) {
        return true;
    }
}

上面就這樣吧。

下面說下session中的flash,我們一般創建完成等操作時,需要給點提示是完成了還是怎么着。在Yii中有自帶flash方法來實現,可點擊這里查看,其實在adminLTE這個后台框架中已集成了Alert小部件,我們可以在backend/views/layout/content.php中發現此小部件的調用<?= Alert::widget() ?>,這是我們只需要在controller中添加setFlash方法,那么就能在view中接收到:

  public function actionCreate()
    {
        $model = new User();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            $session = Yii::$app->session;//session
            $session->setFlash('success', '創建成功');//添加flash
            return $this->redirect(['index']);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

捕捉到的:(adminLTE的alert樣式顏色就是這么深,而Yii框架自帶的顏色雖然淺,但是與此后台框架的顏色也不搭配)

進一步擴展就是,如果是成功的提示,那我5s后可以隱藏,那可以這樣設置,在backend/views/layout/content.php中添加下面漸隱的js代碼

<?php //這是一段,在顯示后定里消失的JQ代碼
    $this->registerJs("
        $('.alert-success').animate({opacity: 1.0}, 5000).fadeOut('slow');
    ");  
?> 

唉?為什么突然說到flash,明顯前后文不統一嗎,差評!主要是,既然有alert形式的flash,那當然也可以用彈窗的方式來展示啊。kartik-v/yii2-dialog雖然有alert、dialog功能,但是在這里都和我想要的不太一樣,所以我們直接調用原生的方法來寫,主要的方法是這樣:(下面有詳細封裝)

var dialogShow=BootstrapDialog.show({
    type:BootstrapDialog.TYPE_SUCCESS, 
    title:'提示消息',
    message:'創建成功,3s后自動關閉',
    size:BootstrapDialog.SIZE_SMALL,
    buttons:[
        {
            label: '關閉',
            action: function(dialogItself){
                dialogItself.close();
            }
        }
    ]
});

我們當然可以直接在index.php中寫,但是東西有點多,最好封裝一下,好吧,那就參照Alert來寫一個Popup的widget來用吧:(一些介紹點這里),在common/widgets中新建Popup.php,直接貼代碼吧。由於只是注冊js,沒有返回值什么的,所以沒有用到run()方法。

 1 <?php
 2 
 3 namespace common\widgets;
 4 
 5 class Popup extends \yii\bootstrap\Widget
 6 {
 7     /**
 8      * 樣式數組
 9      * @var [type]
10      */
11     public $popupTypes = [
12         'default'   => 'BootstrapDialog.TYPE_DEFAULT',
13         'info'  => 'BootstrapDialog.TYPE_INFO',
14         'primary' => 'BootstrapDialog.TYPE_PRIMARY',
15         'success'    => 'BootstrapDialog.TYPE_SUCCESS',
16         'warning' => 'BootstrapDialog.TYPE_WARNING',
17         'danger' => 'BootstrapDialog.TYPE_WARNING'
18     ];
19     /**
20      * 尺寸數組
21      * @var [type]
22      */
23     public $sizeTypes=[
24         'nomal'=>'BootstrapDialog.SIZE_NORMAL',
25         'small'=>'BootstrapDialog.SIZE_SMALL',
26         'wide'=>'BootstrapDialog.SIZE_WIDE',
27         'large'=>'BootstrapDialog.SIZE_LARGE'
28 
29     ];
30     /**
31      * 標題
32      * @var [type]
33      */
34     public $title;
35     /**
36      * 尺寸
37      * @var [type]
38      */
39     public $size;
40 
41     public function init()
42     {
43         parent::init();
44         //默認標題
45         if ($this->title === null) {
46             $this->title = '消息提示';
47         }
48         //默認樣式
49         if ($this->size===null || !isset($this->sizeTypes[$this->size])){
50             $this->size='small';
51         }
52 
53         $session = \Yii::$app->session;
54         $flashes = $session->getAllFlashes();
55 
56         $view = $this->getView();
57 
58         foreach ($flashes as $type => $data) {
59             if (isset($this->popupTypes[$type])) {
60                 $data = (array) $data;
61                 foreach ($data as $i => $message) {
62                     $view->registerJs("
63                         var dialogShow=BootstrapDialog.show({
64                             type:".$this->popupTypes[$type].",
65                             title:'".$this->title."',
66                             message:'".$message."',
67                             size:".$this->sizeTypes[$this->size].",
68                             buttons:[
69                                 {
70                                     label: '關閉',
71                                     action: function(dialogItself){
72                                         dialogItself.close();
73                                     }
74                                 }
75                             ]
76                         });
77                     ");
78                     // 如果是成功,需要增加3s后自動關閉,其余警告等則不需要
79                    if($type=='success'){
80                         $view->registerJs("
81                             setTimeout(function(){ dialogShow.close() }, 3000);
82                         ");
83                    }
84                 }
85 
86                 $session->removeFlash($type);
87             }
88         }
89     }
90 }
太長隱藏

然后在backend/views/layout/content.php引用小部件:

use common\widgets\Popup;
<?= Popup::widget([
    'title'=>'消息',
    'size'=>'small'//參數不寫會有默認值
]) ?>

 看下效果:如果是success,則會自動消失。

那彈出框Popup和提示Alert最大區別是,當存在addFlash方法時,Alert可以依次排列顯示多個,而彈出框Popup則會重復覆蓋顯示,不太友好。當然了在不用addFlash方法時彈出框Popup的顯示更漂亮醒目。

好了,就這樣,睡覺先!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM