팝업 확장 및 구현하기 : Customized PopUp (alert, confirm, loading)

 

 

자바스크립트 내장 함수인 alert, confirm 대화상자를 사용하여 유저에게 알림팝업을 띄우거나, 동의를 구하는 팝업을 띄울 수 있다. 

하지만 팝업 UI를 개발자 마음대로 바꾸는게 불가하며 좀 더 다양한 기능(로딩 팝업 등)을 목적으로 한다면 alert confirm prompt 등의 팝업만으로의 개발에는 한계가 있다.

 

아래와 같이 총 세개의 팝업을 만들어 보자.

alert : 단순알림팝업

comfirm : 확인 및 취소 옵션을 사용자가 선택 할 수 있는 팝업

loading : 로딩(ajax 등의 서버 통신 처리 등)을 하는 동안 떠있는 팝업

 

1. HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div class="popup_bg popup_custom_bg" style="display: none;"></div>
<div class="loadingPopup" style="display: none; text-align:center; padding:20px 10px 10px 10px; width:300px; height:250px;">    
    <span class="msg"></span>
    <div class="popup_cnt" style="padding:30px 0px 0px 0px;">
        <img src = "/resources/img/loading_large.gif" style="width:60px;">    <!-- 로딩 이미지 -->
        <div class="button_wrap">
            <button type="button" class="btn btn_function btn_border btn_popup_ok"><span>대기중단</span></button>
        </div>
    </div>
</div>            
 
<div class="alertPopup" style="display: none; text-align:center; padding:40px 10px 10px; width:300px; height:200px;">    
    <span class="msg"></span>
    <div class="popup_cnt" style="padding:30px 0px 0px 0px;">
        <div class="button_wrap f_r">
            <button type="button" class="btn btn_function btn_border btn_popup_ok"><span>확인</span></button>
        </div>
    </div>
</div>        
 
<div class="confirmPopup" style="display: none; text-align:center; padding:40px 10px 10px; width:300px; height:200px;">    
    <span class="msg"></span>
    <div class="popup_cnt" style="padding:30px 0px 0px 0px;">
        <div class="button_wrap">
            <button type="button" class="btn btn_function btn_red btn_popup_ok"><span>확인</span></button>
            <button type="button" class="btn btn_function btn_border btn_popup_cancel"><span>취소</span></button>
        </div>
    </div>
</div>       
cs

1 Line : 팝업 영역을 제외한 영역에 dim 처리(불투명)를 하기 위한 태그

2~10 Line: loadingPopup

12~19 Line: alertPopup

21~29 Line: confirmPopup 

3, 13, 22 Line : 팝업 내 메시지 출력 영역

5 Line : 로딩팝업 내 로딩이미지 출력 영역

 

 

2. Javascript(jQuery)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
var customPopup = {
 
    open : function(target, mode, msg){
        customPopup.close();
        
        var enterMsg = msg.replace(/\r?\n/g, '<br>');    //엔터 처리
 
        $(target).css("display""block");
        $(target).find(".msg").html(enterMsg);
        
        $(".popup_custom_bg").css("display""block");
    },
    
    close : function(){
        //팝업 전체 지우기
        $(".popup_custom_bg").css("display""none");
        $(".alertPopup").css("display""none");
        $(".confirmPopup").css("display""none");
        $(".loadingPopup").css("display""none");
    },
    
    alert : function(msg, callback){
        //alert 팝업
        $(".alertPopup .btn_popup_ok").unbind("click");
        
        customPopup.open($(".alertPopup"), "alert", msg);
        
        $(".alertPopup .btn_popup_ok").click(function(e){
            customPopup.close();
        });
    },
 
    confirm : function(msg, callback){
        //confirm 팝업
        $(".confirmPopup .btn_popup_ok").unbind("click");
        $(".confirmPopup .btn_popup_cancel").unbind("click");
        
        customPopup.open($(".confirmPopup"), "confirm", msg);
        
        $(".confirmPopup .btn_popup_ok").click(function(e){
            customPopup.close();            
            if(typeof callback != 'undefined' && callback){
                if(typeof callback == 'function'){
                    callback();
                } else {
                    if( callback ) {
                        eval( callback );
                    }
                }
            }
        });
 
        $(".confirmPopup .btn_popup_cancel").click(function(e){
            customPopup.close();
        });
        
    },
 
    loading : function(msg, callback){
        //로딩 팝업
        $(".loadingPopup .btn_popup_ok").unbind("click");
        
        customPopup.open($(".loadingPopup"), "loading", msg);
        
        $(".loadingPopup .btn_popup_ok").click(function(e){        
            if(xhr && xhr.readyState != 4){
                xhr.abort(); //ajax 호출 중단
            }
            customPopup.close();
            if(typeof callback != 'undefined' && callback){
                if(typeof callback == 'function'){
                    callback();
                } else {
                    if( callback ) {
                        eval( callback );
                    }
                }
            }
        });
    }
}
cs

3~12Line : 팝업 띄우기(display block)

14~20Line : 팝업 숨기기(display none) - 특정 팝업이 호출되었을 때(기존에 떠있는 팝업을 지우기 위해), 팝업 내에서 확인/취소/대기중단 버튼이 눌려 팝업이 닫혀야 할 때 마다 호출되는 함수

22~31Line : 알림 팝업

33~51Line : 컨펌 팝업 - 알림팝업과 다르게 확인버튼에 따른 특정 처리가 필요하므로 callback 함수 필요

59~80Line : 로딩 팝업 - 버튼을 누를 경우 ajax.abort(); 로 ajax 처리를 중단한다. ajax 객체를 담고있는 xhr 변수는 전역변수로 선언.

 

 

3. 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function loadingSample(){
    customPopup.loading("로딩 중..."function(){
        //대기 중단
        location.href="/main.do";
    });
}
 
function alertSample(){
    customPopup.alert("성공!");
}
 
function confirmSample(){
    customPopup.confirm("조회하시겠습니까?"function(){
        //ajax 통신
    });
}
 
 
function sample(){
 
    var key = $.trim($("#key").val());
        
    customPopup.confirm("진행하시겠습니까?"function(){
 
        customPopup.loading("처리중입니다."function(){});
                
        var params = {
                said : said
            };
    
        xhr = $.ajax({
            type    : "post",
            url        : "/sample.do",
            contentType: "application/json",
            dataType:"json",
            data     : JSON.stringify(params),    
            success    : function (data) {
                if(data){
                    customPopup.alert("성공");
                } else {
                    customPopup.alert("실패");
                }
            },
            error : function (data, status, err) {
                customPopup.alert("실패");
            }
        });
    });
}
cs

 

※ css 파일은 따로 빠져있고, 관련 부분만 따로 발췌하기 힘들어 대충 인라인 태그에 작성하여 올렸습니다.

 

참고 : https://zzznara2.tistory.com/693

위에 기재한 고수 선배님의 소스를 참고하여 작성하였으며,

위 소스가 복잡하다고 생각하여(제 실력이 미천하여 제겐 너무 어려웠으므로..)

제 수준에 맞게 다시 코딩하였습니다.스크립트 공부는 언제 시작할런지

 

 

※ 위 코드를 조금 더 깔끔하게 수정하였습니다. (20191016)

[script]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<script>
/* 커스텀 팝업 */
var cp_vars = {
    alert : $(".cp_alert"),
    confirm : $(".cp_confirm"),
    loading : $(".cp_loading"),
    bg : $(".cp_bg")    
}
var cp_funcs = {
    
    open : function(target, msg){
        if($(target).length < 1){
            throw new Error("there is no target element !");
        }
        cp_funcs.close();
        
        var enterMsg = msg.replace(/\r?\n/g, '<br>');    //엔터 처리
        
        $(target).css("display""block");
        $(target).find(".msg").html(enterMsg);
        
        cp_vars.bg.css("display""block");
    },
    
    close : function(){
        //팝업 전체 지우기
        cp_vars.bg.css("display""none");
        cp_vars.alert.css("display""none");
        cp_vars.confirm.css("display""none");
        cp_vars.loading.css("display""none");
    },
    
    alert : function(msg, callback){
        //alert 팝업
        cp_vars.alert.find(".btn_popup_ok").unbind("click");
        //$(".cp_alert .btn_popup_ok").unbind("click");
        
        cp_funcs.open(cp_vars.alert, msg);
        
        $(".cp_alert .btn_popup_ok").click(function(e){
            cp_funcs.close();
            if(typeof callback != 'undefined' && callback){
                if(typeof callback == 'function'){
                    callback();
                } else {
                    if( callback ) {
                         eval( callback );
                    }
                }
            } 
        });
    },
 
    confirm : function(msg, callback, callback2){
        //confirm 팝업
        cp_vars.confirm.find(".btn_popup_ok").unbind("click");
        cp_vars.confirm.find(".btn_popup_cancel").unbind("click");
        
        cp_funcs.open(cp_vars.confirm, msg);
        
        $(".cp_confirm .btn_popup_ok").click(function(e){
            cp_funcs.close();            
            if(typeof callback != 'undefined' && callback){
                if(typeof callback == 'function'){
                    callback();
                } else {
                    if( callback ) {
                        eval( callback );
                    }
                }
            }
        });
 
        $(".cp_confirm .btn_popup_cancel").click(function(e){
            cp_funcs.close();
            if(typeof callback2 != 'undefined' && callback2){
                if(typeof callback2 == 'function'){
                    callback2();
                } else {
                    if( callback2 ) {
                        eval( callback2 );
                    }
                }
            }
        });
    },
 
    loading : function(msg, callback){
        //로딩 팝업
        $(".cp_loading .btn_popup_ok").unbind("click");
        
        cp_funcs.open(cp_vars.loading, msg);
        
        $(".cp_loading .btn_popup_ok").click(function(e){
            if(typeof loopFunc != 'undefined'){
                loopFunc.stopLooping();    //Loop 중단
            }
            if(typeof xhr != 'undefined'){
                if(xhr.readyState != 4){
                    xhr.abort(); //ajax 호출 중단
                }
            }
            cp_funcs.close();
            if(typeof callback != 'undefined' && callback){
                if(typeof callback == 'function'){
                    callback();
                } else {
                    if( callback ) {
                        eval( callback );
                    }
                }
            }
        });
    }
}
</script>
cs

수정된 위의 코드는 각 팝업의 레이아웃을 잡는 div node를 전역변수로 선언(3~8 line)하여 사용하고 있으므로

script 로드 순서를 주의해야 합니다.

위 script 소스를 아래의 body 태그보다 아래에 두어야 cp_vars.alert, cp_vars.confirm, cp_vars.loading 변수를 읽는 부분에서 undefined 에러가 나지 않습니다. 스크립트 로드 순서에 따른 문제와 이를 해결하기 위한 방법은 따로 공부를 좀 더 한 후 포스팅 하도록 하겠습니다.

 

[html+css]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<body>
    <!-- 커스텀 팝업 노출시 배경 DIM 처리용 -->
    <div class="popup_bg cp_bg" style="display: none;"></div>
    <!-- 로딩 팝업 -->
    <div class="popup small csPopup cp_loading" style="display: none; text-align:center; padding:20px 10px 10px 10px; width:300px; height:250px;">    
        <span class="msg"></span>
         <div class="popup_cnt" style="padding:30px 0px 0px 0px;">
            <img src = "/resources/img/loading_large.gif" style="width:60px;">    <!-- 로딩 이미지 -->
            <div class="button_wrap">
                 <button type="button" class="btn btn_function btn_border btn_popup_ok"><span>대기중단</span></button>
             </div>
        </div>
    </div>            
    <!-- 알림 팝업 -->
    <div class="popup small csPopup cp_alert" style="display: none; text-align:center; padding:40px 10px 10px; width:300px; height:230px;">    
        <span class="msg"></span>
         <div class="popup_cnt" style="padding:30px 0px 0px 0px;">
            <div class="button_wrap f_r">
                 <button type="button" class="btn btn_function btn_border btn_popup_ok"><span>확인</span></button>
             </div>
        </div>
    </div>        
    <!-- 확인 팝업 -->
    <div class="popup small csPopup cp_confirm" style="display: none; text-align:center; padding:40px 10px 10px; width:300px; height:200px;">    
        <span class="msg"></span>
         <div class="popup_cnt" style="padding:30px 0px 0px 0px;">
            <div class="button_wrap">
                 <button type="button" class="btn btn_function btn_red btn_popup_ok"><span>확인</span></button>
                 <button type="button" class="btn btn_function btn_border btn_popup_cancel"><span>취소</span></button>
             </div>
        </div>
    </div>
</body>
 
cs

 

 

 

 

반응형

+ Recent posts