2012年11月5日 星期一

用Javascript寫Modal Dialog並拖動對話框簡易教學


延續上個例子用Javascript寫Modal Dialog簡易教學
加入底下紅色的程式碼(先不要加上深紅色程式片段),就可以做到移動視窗,簡單的邏輯是:

  1. 在對話框攔截 Mouse Down 事件,記錄當時對話框的位置,與滑鼠位置,與標記「滑鼠已按下」
  2. 在對話框攔截 Mouse Move 事件,根據「滑鼠是否按下」來決定是否移動對話框,移動方式為根據 ( [此時滑鼠位置] - [Mouse Down中的滑鼠位置] + [對話框在Mouse Down中的位置] )來計算出對話框目前應該要在的位置,並且移動之,(透過Java Script
  3. 在對話框攔截 Mouse Up 事件,標記「滑鼠已經放開」

這邏輯很簡單,但你會發現一個瑕疵,就是當你滑鼠移動很快,會讓畫面重繪跟不上,你的滑鼠會超出對話框,然後Mouse事件就不會被處理,所以視窗就不再被移動了。

怎麼解決?加上底下深紅色的程式片段,讓佈滿整個頁面的遮罩層也處理Mouse Move跟Mouse Up,就可以解決了。我不知道這個作法是否完美、正規。如果有人知道更好的、更正確的作法,麻煩告訴我喔,謝謝。


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>

<!-- Script 區段 -->
<script language='JavaScript' type='text/JavaScript'>

$(document).ready(function() 
{
var DivSourceX = 0;
var DivSourceY = 0;
var DivEnvDwX = 0;
var DivEnvDwY = 0;
var DivEnvMvX = 0;
var DivEnvMvY = 0;
var DivMouseFlag = false;    // 用來判斷是否處於滑鼠按著的狀態

// 按下「X」圖隱藏遮罩層
$(".closeDialog").click(function() 
{
ShowModalDialog( false );
});

// 按鈕後顯示遮罩層
$(".btnOpenModal").click(function()
{
ShowModalDialog( true );
});

// 遮罩層控制
function ShowModalDialog( YesOrNo )
{
if ( true == YesOrNo )
{
$(".DivOverlapMask").css( "visibility", "visible" );
$(".DivDialog").css( "visibility", "visible" );
$(".closeDialog").css( "visibility", "visible" );
}
else
{
$(".DivOverlapMask").css( "visibility", "hidden" );
$(".DivDialog").css( "visibility", "hidden" );
$(".closeDialog").css( "visibility", "hidden" );
}
}

// DivDialog 為對話框主體層,需要攔截 Mouse的 Up, Down, Move
$(".DivDialog").mousedown(function(event)
{
DivMouseDown( event );
});

$(".DivDialog").mouseup(function()
{
DivMouseUp( );
});

$(".DivDialog").mousemove(function(event)
{
DivMouseMove( event );
});

// 需要加上遮罩層攔截 Mouse Up 與 Move 才能在「滑鼠意外滑出對話框時,還能繼續移動對話框」
$(".DivOverlapMask").mouseup(function()
{
DivMouseUp( );
});

$(".DivOverlapMask").mousemove(function(event)
{
DivMouseMove( event );
});

// Mouse Down 的時候,紀錄當時視窗的原始位置,滑鼠當時的位置
function DivMouseDown(EvtDw)
{
DivSourceX = $(".DivDialog").position().left;
DivSourceY = $(".DivDialog").position().top;

if ( !EvtDw )
{
EvtDw = window.event;
}

if ( EvtDw.pageX || EvtDw.pageY )
{
DivEnvDwX = EvtDw.pageX;
DivEnvDwY = EvtDw.pageY;
}
else if ( EvtDw.clientX || EvtDw.clientY )
{
DivEnvDwX = EvtDw.clientX;
DivEnvDwY = EvtDw.clientY;
}
else if ( EvtDw.x || EvtDw.y )
{
DivEnvDwX = EvtDw.x;
DivEnvDwY = EvtDw.y;
}

DivMouseFlag = true;
}

function DivMouseUp()
{
DivMouseFlag = false;
}

// Mouse Move 的時候,根據滑鼠的目前位置,原始位置,與物件原始位置,計算,然後將對話框移動到應該去的位置
function DivMouseMove(EvtMv)
{
if ( DivMouseFlag )
{
if ( !EvtMv )
{
EvtMv = window.event;
}

if ( EvtMv.pageX || EvtMv.pageY )
{
DivEnvMvX = EvtMv.pageX;
DivEnvMvY = EvtMv.pageY;
}
else if ( EvtMv.clientX || EvtMv.clientY )
{
DivEnvMvX = EvtMv.clientX;
DivEnvMvY = EvtMv.clientY;
}
else if ( EvtMv.x || EvtMv.y )
{
DivEnvMvX = EvtMv.x;
DivEnvMvY = EvtMv.y;
}

NewDivX = DivSourceX + ( DivEnvMvX - DivEnvDwX );
NewDivY = DivSourceY + ( DivEnvMvY - DivEnvDwY );

$(".DivDialog").css(
{
top: NewDivY + "px",
left: NewDivX + "px"
});

}
}
})
</script>


<!-- CSS 區段 -->  
<style type="text/css">

/* 只是背景 */
.DivGround
{
position: absolute;
width: 400px;
height: 300px;
top: 30px;
left: 30px;
border: solid;
background-color: #66ccff;
text-align:center;
}

/* 遮罩,將整個瀏覽器佈滿,讓原本背景層都無法點選 */
.DivOverlapMask
{
position:fixed;
top:0px;
left:0px;
height:100%;
width:100%;
margin:0;
padding:0;
background:gray;
opacity:0.95;
visibility:hidden;
}

/* Modal Dialog 層 */
.DivDialog
{
position:absolute;
width:200px;
height:100px;
margin:0;
padding:0;
left:100px;
top:100px;
    background-color: #eeaaaa;
border-radius: 10px;
visibility:hidden;
}


/*「X」按鈕 */
.closeDialog
{
position:absolute;
width:32px;
height:32px;
right:8px;
top:8px;
cursor:pointer;
visibility:hidden;
}
</style>


<title>無標題文件</title>
</head>



<body>
    <!-- Modal Dialog 的原理就是在背景層(可以很多層)之上,蓋上一層遮罩,最後給一個DIV當成對
    話框 -->
    
<div class= "DivGround">
        <button class = "btnOpenModal" > 開 啟 </button> 
        <div class = "DivOverlapMask" >
            <div class = "DivDialog" >       
                <img class = "closeDialog" src="img/close-button.png" ></img>            </div>
        </div>
    </div>
</body>
</html>

沒有留言:

張貼留言