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>

2012年11月4日 星期日

用Javascript寫Modal Dialog簡易教學


為了讓程式畫面美觀,底下程式碼會稍微多了點,但其實,方法與原理不難。


  1. 把網頁主體先完成之後,準備好一個按鈕,或某個觸發的點,可以觸發事件。
  2. 在主體層上堆一層「遮罩層」。這層設定寬、高都是100%,然後設定透明度opacity:0.85或0.95(自己看喜歡怎樣的感覺來調整);然後這層在包含著DIV,這個DIV就是用來當對話框用的,你可以在這個DIV當中繼續包入其他元素,記得要包含個按鈕或圖示可以把對話框「關掉」的。
  3. 將「遮罩層」設定好一個控制函式,根據傳入參數來設定「遮罩層」,來把「遮罩層」給隱藏或打開來。




<!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'>


// 按下「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" );
}
}

})
</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.85;
filter: alpha(opacity=85);
-moz-opacity: 0.85;
visibility:hidden;
}

/* Modal Dialog 層 */

.DivDialog
{
position:fixed;
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>

使用圖片檔的時候,無法(也不要)寫在CSS裡

我雖然不知道原因
但是網路上查到的資訊是這樣告訴我的,如果有錯,麻煩可以回文告訴我一下

img 這個 tag,如果你要把圖片來源 src = "xxxx.png" 寫在CSS裡,是沒有辦法的,應該說,寫了沒有用。雖然 Dreamwave 的 intelligent senses 還是會引導你在 CSS 的程式片段中幫你引導出 Src 的程式類似這樣:src:url(img/close-button.png);可是,實際執行,圖片就是不會出來。



解法一:

在 CSS 中不要用 src 屬性,而改用 background-image 屬性,當然,您也想到了,這樣很怪,且,這樣圖片會多出一個外框,無法消掉.......,這樣不算解決方案。


解法二:

不要寫在 CSS 當中,直接寫在 HTML 裡<img class = "ImgStyle" src="img/button.png" ></img>,這樣就解決了,只是,這個無法放到CSS當中,不知道的人,可能得花好久的時間才找得出原因呢。

CSS的註解是 /* xxxx */ 而不是 別弄錯呀

因為Dreamwave CS6 有對程式碼做 色彩區分
所以我相信他所以當我用 <!-- xxxx --> 來加註解的時候,該段程式碼確實變成灰色,但是.......
實際上,他不是變成註解,導致整個CSS片段都被當成錯誤的而跳過
意外的多花費了我一個上午的時間找出為什麼我的 DIV 都突然無法正常呈現大小。

後來查很久才知道,原來是註解寫法寫錯了(昏)


2012年11月2日 星期五

MouseDown之後的MouseMove時(拖動),控制滑鼠游標注意事項


底下這段程式碼最下方body內有四行被遮住的,可以逐一打開其中一個來感受一下,當你滑鼠游標滑入該物件裡面時,滑鼠游標會變成十字移動圖示,但是當你按著滑鼠移動,就會有不同了,在div跟table會顯示為輸入文字的符號,而在button跟img則顯示為移動的十字符號。怎麼回事?這是因為,前兩者是可包容其他物件的區塊物件,用來排版的,而後兩者是不可包容其他物件在其中的功能物件,系統預設按著滑鼠移動叫做拖動,而針對上述兩種類型的物件都預設了滑鼠的圖示,而且無法改(目前我還不會)。

所以如果要拖動物件,而且拖動的對象是個區塊物件,譬如拖動視窗,那會做不出效果來,建議可以放個功能物件在區塊物件上,就像是放個標題列一樣意思,讓使用者在功能物件上按下滑鼠,才觸發移動,並對區塊物件做移動,這樣就行了。



<!doctype html> 

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Mouse Move</title>
    <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
    
<!-- Script 區段 -->
<script>
    $(document).ready(function(e) 
    {   
$(".TheObj").mousemove(function(e)
{
$(".TheObj").text( "mouse moving" );
$(".TheObj").css( "cursor", "move" );
});
})
        </script>
    
<!-- CSS 區段 -->    
<style type="text/css">
        .TheObj
        {
            width:600px;
            height:400px;
            border:solid;
            cursor:pointer; 
        }​
        </style>

</head>



<!-- Body 區段 -->

<body>
        <!-- <div class = "TheObj"></div>​             --> 
        <!--  <table class = "TheObj"></table>​        -->         
        <!--  <button class = "TheObj"></button>​   --> 
        <!--  <img class = "TheObj"></img>​            --> 
     
</body>
</html>

2012年11月1日 星期四

iframe是無法處理事件的


iframe是無法處理事件的,首先,你在Tag裡頭,想輸入<iframe onClick = "aFunc()"如果你在Dreamwave 或 Visual Studio 這類有 intelligent senses(忘記是不是這樣拼了)的提示功能的開發工具,你會發現他的提示當中,並沒有onXXXXX,也就是他不處理事件。而且如果想透過JQuery的方式來加入事件跟函式的關連,你會發現,intelligent senses有提示你Enevt可用,但是寫了之後,沒有作用。

你可以用底下的程式碼執行在瀏覽器看看,在body內,有遮掉三行,分別為div, span, iframe,你可以個別打開看看,會發現只有iframe沒有作用。所以,盡量不要在你的架構上「需要去處理iframe」的Event,不然,就不要用iframe了,把該頁面直接寫在這個HTML或PHP就好了。


當然,Google一下,你也會找到解法,比方從iframe內部的頁面傳事件到Parent來,或用AddListener之類的方式,但是有比較困難,暫時還是先避開就好吧。



<!doctype html> 

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>jQuery (document).ready 教學</title>
    <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
<!-- CSS 區段 -->    
    
    <script language="javascript">
    $(document).ready(function(e) 
    {   
$("body").click(function(e)
{
alert('Mouse Click body.')
$(".OutScreen").text( "Click body" );
});

$(".button").click(function(e)
{
alert('Mouse Click button.')
$(".OutScreen").text( "Click button" );
});
 
$(".OutScreen").click(function(e)
{
alert('Mouse Click Screen.')
$(".OutScreen").text( "Click Screen" );
});
});
    </script>
    
    
    <!-- CSS 區段 -->
<style type="text/css">
.OutScreen
{  
width:600px;
height:400px;
border:solid;
background:#FF6;
}​
    </style>
</head>

    <body>

       這個網頁展示的是在 Body 主體上,放了一個按鈕,跟一個來比較的物件,可發現,iframe是無法處理事件的<br>
       <!--<iframe class="OutScreen" >xxxxx</iframe>-->
       <!--<span class="OutScreen" >xxxxx</span>-->
       <!--<div class="OutScreen" >xxxxx</div>-->

       <button class = "button">按鈕</button> <br>

    </body>

</html>






FireFox與JavaScript的不相容:MousePosition與MouseEvent



  • 先看Event吧

$(".DivDialogTitle").click(function (e) { DivClick(event); });

這種JQuery的寫法,可以把某個TAG物件的Click事件跟某個指定的函式關連在一起,可正常運作,沒有問題。



$(".DivDialogTitle").mousedown(function (e) { DivMouseDown(event); });

但是想把Mouse的事件跟某個指定的函式關連在一起,抱歉,FireFox辦不到(以後會不會更新成可支援,不曉得)



該怎麼做?得回到最原始的HTML語法在Tag中把事件跟函式綁定

<div onmouseup = "DivMouseUp(Event)" >

是的,改成這樣就行了

-------------------------------------------------------------------------------------------



  • 再看滑鼠位置吧

事件函式假設如下


function DivMouseDown(e)

{
     // 如果 e 是 null (有時候吧,意外發生),就把 e 設定為 window 的 event
     if ( !e )
     {
        e = window.event;
     }
     
     var IeMousePosition = e.X;
     
     var FireFoxMousePosition = e.PageX;
}


如上頭所列,想取得Mouse的位置,如果是IE或Chrome或Safari或Opera,你可以這麼用:e.X。如果是FireFox,那你得用e.PageX。