一、事件對象event
1.1 preventdefault()和returnValue阻止默認事件
通知瀏覽器不要執行與事件關聯的默認動作。
preventdefault() 支持Chrome等高級瀏覽器
returnValue 支持IE6、7、8
var box = document.getElementById('box');
var i = 0;
//鼠標在box盒子滾動時觸發
box.onmousewheel = function(event){
var event = event || window.event;
//能力檢測,阻止默認事件
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = true;
}
this.innerHTML = '你在我身上滾動了!' + i++;
}
1.2 stopPropagation()和cancelBubble阻止事件繼續傳播
stopPropagation() 支持Chrome等高級瀏覽器
cancelBubble 支持IE6、7、8
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');
box1.onclick = function(){
alert('box1');
}
box2.onclick = function(event){
alert('box2');
//阻止事件繼續傳播,能力檢測
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
box3.onclick = function(){
alert('box3');
}
二、BOM
瀏覽器對象模型(browser object model)
2.1捲動事件
當窗口無論向上向下捲動的時候,比如鍵盤↓了,滾動鼠標滾輪,拖拽滾動條,都會觸發這個事件。
window.onscroll=function(){
}
2.2窗口的寬度和高度
認識一個對象:
document.documentElement |
就是頁面document,想要得到窗口的寬度和高度,不是window對象,而是document對象,所以:
document.documentElement.clientWidth document.documentElement.clientHeight |
但是去掉頁面DTD,或IE678瀏覽器中,把下面的語句當做瀏覽器窗口的寬度和高度
document.body.clientWidth document.body.clientWidth |
所以兼容語法:
document.documentElement.clientWidth || document.body.clientWidth; document.documentElement.clientHeight || document.body.clientWidth; |
2.3窗口的捲動值
兼容語法:
document.documentElement.scrollTop || document.body.scrollTop |
兼容所有瀏覽器
document.documentElement.scrollTop |
兼容不寫DTD的情況下:
document.body.scrollTop |
三、鼠標位置
當我們給某一個盒子添加鼠標事件監聽時(click、mouseover、mouseenter、mouseout等事件),都一定會有以下四組值:
event.pageX event.pageY event.screenX event.screenY event.clientX event.clientY event.offsetX event.offsetY |
event.pageY 表示鼠標指針,到頁面頂端的距離。IE6、7、8不兼容
event.screenY 表示鼠標指針,到屏幕頂端的距離
event.clientY 表示鼠標指針,到視口頂端的距離(視口就是當前可視窗口)
event.offsetY 表示鼠標指針,到盒子頂端的距離
規律:
1、當頁面沒有捲動的時候,pageY一定等價於clientY。或換句話說pageY等價於clientY+頁面捲動的值scrollTop。
2、IE678不兼容pageX、pageY
3、offsetX/Y會被兒子影響。
offsetX/Y指的不是距離你監聽的那個盒子左上角的距離,而是指的你現在鼠標指針所在位置到此時最內層盒子左上角的距離。
四、盒子位置
任何一個元素都有offsetParent屬性,和offsetLeft、offsetTop屬性
4.1計算盒子在頁面中的淨位置
現在我們就可以用offsetParent和offsetTop/Left計算一個元素的淨位置了,是一個迭代的過程。
xiaoming的淨位置:xiaoming.offsetTop + xiaoming.offsetParent的xiaoming.offsetParent.borderTop ...
由於IE8很特殊,所以我們迫切的需要知道瀏覽器是不是IE8。所以使用:
window.navigator.userAgent
來檢測瀏覽器的版本。
|
|
var ie8 = window.navigator.userAgent.indexOf("MSIE 8.0") != -1; |
下面的函數就是得到一個元素在頁面上的總淨位置:
function offset(o){
//初始值
var result = {
"top" : o.offsetTop,
"left" : o.offsetLeft
}
//判斷瀏覽器是不是IE8
var isIE8 = window.navigator.userAgent.indexOf("MSIE 8.0") != -1;
//循環迭代,尋找父親
while(o = o.offsetParent){
//計算後的邊框的值
if(window.getComputedStyle){
var borderTop = parseInt(getComputedStyle(o)['border-top-width']);
var borderLeft = parseInt(getComputedStyle(o)['border-left-width']);
}else{
var borderTop = parseInt(o.currentStyle['borderTopWidth']);
var borderLeft = parseInt(o.currentStyle['borderLeftWidth']);
}
//驗證一下,萬一borderTop是undefined或NaN,此時修正爲0
if(isNaN(borderTop)){
borderTop = 0;
}
if(isNaN(borderLeft)){
borderLeft = 0;
}
//如果瀏覽器版本不是IE8那麼就加上邊框,如果是IE8就不需要加邊框,拋出自己
!isIE8 && (result.top += borderTop);
!isIE8 && (result.left += borderLeft);
result.top += o.offsetTop;
result.left += o.offsetLeft;
}
return result;
}
4.2曲線救國得到鼠標在盒子中的位置:
var box = document.getElementById("box");
var result = document.getElementById("result");
//監聽父親鼠標移動的時候,鼠標指針的offsetX值和offsetY值
box.onmousemove = function(event){
var event = event || window.event;
var x = event.pageX - getAllOffset(box).left;
var y = event.pageY - getAllOffset(box).top;
result.innerHTML = x + "," + y;
}
由於IE低版本不兼容pageX和pageY,所以用clientX/Y加上捲動值:
var box = document.getElementById("box");
var result = document.getElementById("result");
//監聽父親鼠標移動的時候,鼠標指針的offsetX值和offsetY值
box.onmousemove = function(event){
var event = event || window.event;
//曲線救國!!!!得到窗口捲動的值
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
//鼠標的offsetX、offsetY等於視口的值,加上捲動值減去淨位置。
var x = event.clientX + scrollTop - getAllOffset(box).left;
var y = event.clientY + scrollLeft - getAllOffset(box).top;
result.innerHTML = x + "," + y;
}
五、拖拽
5.1 在頁面上拖拽
頁面上的元素,能夠被鼠標拖拽。整體思路:
① 當鼠標在img上按下去的時候,註冊document的鼠標移動事件監聽;反之,當鼠標在屏幕任何位置擡起的時候,剝奪document的鼠標移動事件監聽。
② 爲了讓鼠標能夠一直按住圖片的同一個位置,所以要在mousedown的一瞬間記錄誤差(見下圖)。
var img = document.getElementsByTagName('img')[0];
//鼠標指針在圖片上按下的時候
img.onmousedown = function(event){
var event = event || window.event;
//記錄誤差,目的是當我按住baby的腦門子拖拽的時候,鼠標指針一直在腦門子上。
var dx = event.offsetX;
var dy = event.offsetY;
//註冊新的事件
//在document上移動的時候,讓img跟隨鼠標
document.onmousemove = function(event){
var event = event || window.event;
//移動的時候top值等於當前的鼠標指針位置減去開始的時候的誤差
var x = event.clientX - dx;
var y = event.clientY - dy;
img.style.left = x + "px";
img.style.top = y + "px";
//這個return false可以解決IE8的內置事件
return false;
}
//這個return false可以解決IE8的內置事件
return false;
}
//鼠標指針在任何位置擡起的時候,刪除document上的move監聽
document.onmouseup = function(){
document.onmousemove = null;
}
5.2在容器中拖拽
圖片在父級容器中拖拽的時候,不僅僅是給圖片加了一個限制區域,圖片的top、left參考點是父盒子左上角,鼠標指針的位置點就不一致。圖片的top、left起點是A,而鼠標指針clinetX、Y參考點是B點。
大家參考點就不一樣了。
方法:只要把它們的座標統一就可以了,所以我們需要得到鼠標指針相對於盒子的座標位置,此時需要使用曲線救國,因爲offsetX/Y會被兒子影響。
var img = document.getElementsByTagName('img')[0];
var box = document.getElementById('box');
//得到盒子的淨位置
var boxoft = offset(box).top;
var boxofl = offset(box).left;
console.log(boxoft,boxofl)
//鼠標指針在圖片上按下的時候
img.onmousedown = function(event){
var event = event || window.event;
//記錄誤差,目的是讓我按住baby的腦門拖拽的時候,鼠標指針一直在腦門上
var dx = event.offsetX;
var dy = event.offsetY;
//鼠標按下,然後執行鼠標移動時間,接着在document上移動,讓img跟着移動
document.onmousemove = function(event){
var event = event || window.event;
//曲線救國!!!!得到窗口捲動的值
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft|| document.body.scrollLeft;
//鼠標的offsetX、offsetY等於視口的值,加上捲動值減去淨位置
//移動的時候top值等價於鼠標指針位置減去開始按下的誤差
var X = event.clientX + scrollLeft - boxofl - dx;
var Y = event.clientY + scrollTop- boxoft - dy;
console.log(X,Y)
//驗收
if(X > 300){
X = 300;
}else if(X < 0){
X = 0;
}
if(Y > 300){
Y = 300;
}else if(Y < 0){
Y = 0;
}
img.style.left = X+'px';
img.style.top = Y+'px';
//這個return false可以解決瀏覽器內置事件
return false;
}
}
//在鼠標指針任何位置擡起的時候,移除document上的move事件監聽
document.onmouseup = function(){
document.onmousemove = null;
}
5.3放大鏡效果
和剛剛的拖拽不一樣,鼠標指針不需要按下了,所以邏輯變得簡單了。
放大鏡的放大原理:不是真的放大,只是當左邊小放大鏡移動的時候,右邊的大圖按比例移動,形成放大的感覺。
比例問題:
小圖盒子350寬高,放大鏡175寬高
大圖盒子400寬高,圖片800寬高
這裏暗含了兩個1:2,比例一定要相同,如果比例不相同,放大鏡放大感覺就不一樣了,無法看全。
六、鼠標滾輪事件
頁面中經常有鼠標滾輪事件,比如做一個內置有縱向滾動條的盒子
Chrome和IE各個版本瀏覽器都支持onmousewheel事件,表示鼠標滾輪滾動的時候觸發,火狐不支持這個事件,它支持的是自己的DOMMouseScroll事件,我們不需要進行能力檢測,因爲所有的瀏覽器遇見別人添加監聽的方法都不報錯(靜默)。
var box = document.getElementById('box');
//除了火狐瀏覽器之外,都支持以下這種監聽滾輪事件
box.onmousewheel = mousewheel;
//火狐獨有的,必須用DOM2級添加監聽
box.addEventListener('DOMMouseScroll',mousewheel,true);
//事件處理函數
function mousewheel(){
alert('滾動了!!!');
}
鼠標滾輪事件的event對象有屬性wheelDelta,火狐是detail屬性,可以反映你的滾輪方向和力度
非火狐向上120(力度越大數字越大),火狐向上是-3
非火狐向下-120(力度越大數字越大),火狐向上是3
所以要進行兼容性處理,把它們的值統一爲:1和-1
box.onmousewheel = mousewheel;
//火狐獨有的,必須用DOM2級添加監聽
box.addEventListener('DOMMouseScroll',mousewheel,true);
//事件處理函數
function mousewheel(event){
//進行方向的能力檢測,由於火狐和大家不一樣,用if分開判斷
if(event.wheelDelta){
//非火狐
// if(event.wheelDelta > 0){
// var direction = 1;
// }else{
// var direction = -1;
// }
var direction = event.wheelDelta > 0 ? 1 : -1;
}else{
//火狐
// if(event.detail > 0){
// var direction = -1;
// }else{
// var direction = 1;
// }
var direction = event.detail > 0 ? -1 : 1;
}
console.log(direction)
}
上一篇文章DOM2級小測試的正確答案:EFGHIBCD
解釋:
1、DOM0級只能添加到冒泡階段
2、DOM0級事件同名的會覆蓋
3、true表示捕獲,false表示冒泡,先捕獲,後冒泡
4、DOM2級的不會覆蓋,先寫的先執行
5、DOM2級最內層的不區分冒泡和捕獲,誰先寫誰執行,無論是DOM0還是DOM2。