Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2311

使用自訂確認對話框取代window.confirm

$
0
0

專案規格有一條機車要求: 對於刪除或覆寫資料前的確認程序,希望以自訂風格的確認對話框取代簡陋的window.confirm()。

舉例來說,按鈕後原本要透過window.confirm()請使用者確認後再執行,現在要改用自訂HTML元素呈現確認文字、按鈕進行確認,就如以下改用Kendo UI Window實作確認對話框的效果:

用HTML打造自訂對話框並在適當時機顯示是小事一椿,較有挑戰性的部分是原本window.confirm()執行為同步式,程式碼會停住等使用者回應再繼續往下走。想依confirm()結果決定不同動作只需寫成:

if (window.confirm("確定嗎?")) {
    //…使用者回答【是】時的動作
} else {
    //…使用者回答【否】時的動作
}

但要在JavaScript做到"卡住流程直到特定條件再繼續"並非易事,曾看過一種做法是跑while無窮迴圈並於特定時機跳出,但因JavaScript不像C#有Thread.Sleep可用,無窮迴圈會莫名吃光CPU很不環保。也有人想出藉由同步式XHR到Server端存取虛設延遲網頁模擬Thread.Sleep的招術,但靠著無謂網路傳輸來節省CPU,還徒增Server負擔,想來也不怎麼高明。最後,還是決定用jQuery的Deferred來處理非同步。

原理是先宣告Deferred物件,當呼叫確認對話框時,傳回Deferred.promise()給呼叫端,呼叫端可透過.done()指定使用者按【是】時要執行的動作、在.fail()指定使用者按【否】時要執行的動作。如此,再依使用者按鈕決定呼叫Deferred.resolve()或Deferred.reject(),就能控制該觸發done()還是fail(),達到依操作結果決定不同執行動作的效果。先不管華麗的UI元素,以下是示範用Deferred依按鈕結果決定動作的簡單範例: 線上展示

<!DOCTYPEhtml>
<html>
<head>
<scriptsrc="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js"></script>
<meta charset=utf-8 />
<title>使用Deferred建立自訂確認對話框</title>
<script>
function myConfirm(msg) {
var df = $.Deferred(); //建立Deferred物件
var $div = $("<div id='C'></div>");
//由樣版複製建立一次性div元素
      $div.html($(".dialog").html())
//加上按鈕事件
      .on("click", "input", function() {
        $div.remove(); //將對話框移除
if (this.value == "Yes") 
          df.resolve(); //使用者按下Yes
else
          df.reject(); //使用者按下No
      })
      .find(".m").text(msg); //設定顯示訊息
//將div加入網頁
      $div.appendTo("body");
return df.promise();
    }
    $(function() {
      $("#btnTest").click(function() {
        myConfirm("Are you sure?")
        .done(function() { //按下Yes時
          alert("You are sure");
        })
        .fail(function() { //按下No時
          alert("You are not sure");
        });
      });
    });
</script>
</head>
<body>
<inputtype='button'value='Test'id='btnTest'/>
<divclass='dialog'style='display:none'>
<divstyle='border: 1px solid blue; padding: 12px;'>
<spanclass='m'></span>
<inputtype='button'value='Yes'/>
<inputtype='button'value='No'/>
</div>
</div>
</body>
</html>

其操作結果如下:

最後,運用同樣原理再招喚Kendo UI的Window套件上場,就能實現一開始展示的華麗版確認對話框囉~ 完整程式碼如下: 線上展示

<!DOCTYPEhtml>
<html>
<head>
<title>使用Deferred建立自訂確認對話框(Kendo UI版)</title>
<linkhref="http://cdn.kendostatic.com/2013.2.716/styles/kendo.common.min.css"
rel="stylesheet"type="text/css"/>
<linkhref="http://cdn.kendostatic.com/2013.2.716/styles/kendo.default.min.css"
rel="stylesheet"type="text/css"/>
<scriptsrc="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js"></script>
<script src="http://cdn.kendostatic.com/2013.2.716/js/kendo.web.min.js"></script>
<meta charset=utf-8 />
<style>
    .cnfrm-msg { color: red; padding: 12px; font-size: 12pt; }
    .cnfrm-yes,.cnfrm-no { }
</style>
<script>
//參考: http://jsfiddle.net/gyoshev/HRcKK/
    (function($) {
var h = [];
      h.push("<div class='cnfrm-block'>");
      h.push("<div class='cnfrm-msg'></div>");
      h.push("<input type='button' class='cnfrm-yes' />");
      h.push("<input type='button' class='cnfrm-no' />");
      h.push("</div>");
var html = h.join("");
      $.kendoConfirm = function(title, msg, yesText, noText) {
var $div = $(html);
        $div.find(".cnfrm-msg").text(msg);
        $div.find(".cnfrm-yes").val(yesText || "Yes");
        $div.find(".cnfrm-no").val(noText || "No");
var win = $div.kendoWindow({
          title: title || "Confirmation",
          resizable: false,
          modal: true,
          deactivate: function() {
this.destroy(); //remove itself after close
          }
        }).data("kendoWindow");
        win.center().open();
var dfd = $.Deferred();
        $div.find(":button").click(function() {
          win.close();
if (this.className == "cnfrm-yes")
            dfd.resolve();
else
            dfd.reject();          
        });
return dfd.promise();
      };
    })(jQuery);
    $(function() {
      $("#btnTest").click(function() {
var dfd = 
        $.kendoConfirm(
"Please confirm...",
"Are you sure to delete it?",
"Yeeees", "No no no");
        dfd.done(function() { //按下Yes時
          alert("You are sure");
        })
        .fail(function() { //按下No時
          alert("You are not sure");
        });
      });
    });
</script>
</head>
<body>
<inputtype='button'value='Test'id='btnTest'/>
<divclass='dialog'style='display:none'>
<divstyle='border: 1px solid blue; padding: 12px;'>
<spanclass='m'></span>
<inputtype='button'value='Yes'/>
<inputtype='button'value='No'/>
</div>
</div>
</body>
</html>

Viewing all articles
Browse latest Browse all 2311

Trending Articles