標籤:
有時候項目中會用到用js擷取元素位置來定位元素,我在網上開了大量的 圖解,代碼,最終把我搞的暈了,還是結合網上的 自己來總結一下,首先來看看網上的:
DOM的定義如
scrollLeft:設定或擷取位於對象左邊界和視窗中目前可見內容的最左端之間的距離
scrollTop:設定或擷取位於對象最頂端和視窗中可見內容的最頂端之間的距離
scrollWidth:擷取對象的滾動寬度
offsetHeight:擷取對象相對於版面或由父座標 offsetParent 屬性指定的父座標的高度
offsetLeft:擷取對象相對於版面或由 offsetParent 屬性指定的父座標的計算左側位置
offsetTop:擷取對象相對於版面或由 offsetTop 屬性指定的父座標的計算頂端位置
event.clientX 相對文檔的水平座標
event.clientY 相對文檔的垂直座標
event.offsetX 相對容器的水平座標
event.offsetY 相對容器的垂直座標
document.documentElement.scrollTop 垂直方向滾動的值
擷取元素的位置屬性可以通過
- HTMLElement.offsetLeft
- HTMLElement.offsetTop
但是,這兩個屬性所儲存的數值並不是該元素相對整個瀏覽器畫布的絕對位置,而是相對於其父元素位置的相對位置,也就是說這兩個數值得到的是以其 父元素左上方為(0,0)點從而計算出的數值。所以我們要得到她的絕對位置,那麼我們必須依次向上擷取他的父元素的位置,然後擷取它父元素的父元素的offersetLeft和offersetTop,一直遞迴到瀏覽器的整個畫布橫縱距離的時候,例如( 一定注意是相對於父標籤的途徑!)
/*擷取元素的縱座標*/function getTop(e){ var offset=e.offsetTop; if(e.offsetParent!=null){ offset+=getTop(e.offsetParent); } return offset;}/*擷取元素的橫座標*/function getLeft(e){ var offset=e.offsetLeft; if(e.offsetParent!=null){ offset+=getLeft(e.offsetParent); } return offset;}擷取元素的絕對位置,無非是根據元素距瀏覽器左邊(left)和頂部(top),我們可以稍稍改變一下得到一方法
function getElemPos(obj){ var pos = {"top":0, "left":0}; if (obj.offsetParent){ while (obj.offsetParent){ pos.top += obj.offsetTop; pos.left += obj.offsetLeft; obj = obj.offsetParent; } }else if(obj.x){ pos.left += obj.x; }else if(obj.x){ pos.top += obj.y; } return {x:pos.left, y:pos.top};}event.clientX+document.documentElement.scrollTop 相對文檔的水平座標+垂直方向滾動的量
以上主要指IE之中,FireFox差異如下:
IE6.0、FF1.06+:
clientWidth = width + padding
clientHeight = height + padding
offsetWidth = width + padding + border
offsetHeight = height + padding + border
IE5.0/5.5:
clientWidth = width - border
clientHeight = height - border
offsetWidth = width
offsetHeight = height(需要提一下:CSS中的margin屬性,與clientWidth、offsetWidth、clientHeight、offsetHeight均無關)
上面的紅色部分以經講的很清楚 offsetwidth,現在裡看看
在說說, scrollLeft :設定或擷取位於對象左邊界和視窗中目前可見內容的最左端之間的距離。
在說之前 首先來看一段文字:
scrollLeft:設定或擷取位於對象左邊界和視窗中目前可見內容的最左端之間的距離。
1、innerHTML:inner(裡面,元素),innerHTML是用來改變對象DH內部的HTML語句。而此效果中我們所用到的a.innerHTML=b.innerHTML就是b將自己的HTML元素賦予a,用在這裡就如複製一說。
2、offsetWidth:是指對象包括邊框在內的寬度。與clientWidth不同,clientWidth指對象不包括邊框只包括內容的實際寬度。
3、scrollLeft:我們知道scroll是捲軸,那麼scrollLeft就是指捲軸自左向右滾出時距離左邊起點的距離。scroll有四個方向,大家依次類推。
瞭解了這三項基本屬性,我們就有了初步實現滾動的思想。首先我們要知道一個塊就有這麼寬,如果裡面的內容也和外邊包裹它們的父標籤寬度一樣的話,那麼滾動 條的寬度肯定也與內容一樣寬,根本就沒得滾。只有在裡面內容大於父標籤內容並且對父標籤設定完固定寬進行超出部分隱藏。這樣即使在我們並沒有控制js時也 是可以實現手動拖拉捲軸的。瞭解這點後再說迴圈滾動,既然子標籤要超出父標籤才能實現滾動,那麼迴圈滾動,迴圈展示一組圖片不就是需要兩組一模一樣的圖 片首尾相接,當第一塊的尾部滾過後第二塊的首部立馬相接,當然控制好精確到1px時,使用者是根本察覺不到是兩組圖片在做滾動,因為是相同的。說完原理,再 說實現辦法,我們已經知道了scrollLeft的意思,那麼要讓圖片向左滾,無疑就是增加它的數值,在我們手動拖拉捲軸時也會觀察到向右拖拉時圖片是想做移動的,scrollLeft的距離在不斷增加。那麼也就是說,要實現子標籤圖片的滾動,就要控制父標籤的scrollLeft。再加上計時器,讓父標籤的scrollLeft每過多久增加多少不久實現了自動的圖片滾動了嗎?下面請看代碼吧,在HTML的結構上也是需要做下詳解的。
這是 一段網上找到,要清楚scrollleft 是父標籤的,scrollleft是個值,父標籤就是指的產生捲軸這個元素,,而捲軸也屬於,父標籤。
下面來看一個簡單的例子:
HTML:<div id="div1"><div id="div2"><!-- 這裡的div主要起控制不換行的作用,因為裡面還要包裹兩個div --><div id="div3"><a href="#"><img src="images/tu1.jpg" /></a><a href="#"><img src="images/tu2.jpg" /></a><a href="#"><img src="images/tu3.jpg" /></a><a href="#"><img src="images/tu4.jpg" /></a><a href="#"><img src="images/tu5.jpg" /></a></div><div id="div4"> </div></div></div>
使 用table製作還能減少css樣式的設定,省去很多浮動。但是table中的td元素之間的間距是需要解決的,如以上代碼中已經寫到在包裹圖片的 table標籤中加入cellspacing="0" cellpadding="0",當然也可以直接在css中這樣寫,table{border-collapse:collapse;},便可去除td之 間的間距,圖片折行引起的間距使用浮動解決,同時我們還要養成的習慣便是當子項目浮動後要對其父標籤設定overflow:hidden;否則其父標籤將 不再包裹子標籤,加border後便可看到。
css:body {margin:0;}#div {border:5px #0ff solid;height:160px;width:800px;overflow:hidden;overflow-x:scroll;}#div table td {overflow:hidden}#div img {float:left;}
js:<script type="text/javascript">vardiv=document.getElementById("div");//最外層divvar td1=document.getElementById("td1");//第一個td,裡麵包裹圖片var td2=document.getElementById("td2");//沒有包裹內容(圖片)的tdtd2.innerHTML=td1.innerHTML;//將第一個td中的內容賦予第二個tdfunction hs1(){div.scrollLeft++;//外圍父標籤div的scrollLeft加加(上文有詳解)}var id=setInterval(hs1,10);//每過10毫秒加1,從而初步實現滾動</script>
有了上述一個開端實現了圖片的初步滾動,我們能觀察到當捲軸滾到右邊盡頭時就不再滾動了,我們又如何讓它從頭繼續滾動呢?請看下列代碼:(接上述代碼做延伸)
<script type="text/javascript">vardiv=document.getElementById("div");vartd1=document.getElementById("td1");vartd2=document.getElementById("td2");td2.innerHTML=td1.innerHTML;functionhs1(){if(td1.offsetWidth<=div.scrollLeft){//捲軸停了,圖片必定也滾到盡頭了,這時就判斷第一個或第二個(二者同寬)//的寬度(或加邊或不加邊)是不是已經大於或等於父標籤div的scrollLeftdiv.scrollLeft=0;//如果上述條件成立,那麼div的scrollLeft就從零開始}else{div.scrollLeft++;//不屬上述情況時就繼續++}}var id=setInterval(hs1,10);</script>
運 行到這裡就已經實現了無縫滾動,那麼接下來要考慮的就是當使用者滑鼠放上時停止滾動,離開時繼續滾動。思想也很容易理解,就是放上時清除計時器,離開時再加 上計時器。其實不用事件監聽的話要做到這一步只需兩句話,很容易。但是為了防止事件冒泡,我們還是需要使用時間監聽的方法解決。
事件冒泡:css中,子標籤會繼承父標籤的樣式。js中,由於很多瀏覽器是沒有分層的,不能分層解析,子標籤就會繼承父標籤的動作造成事件冒泡。所以我們要盡量阻止冒泡。
接上述代碼延伸:
<script type="text/javascript">vardiv=document.getElementById("div");vartd1=document.getElementById("td1");vartd2=document.getElementById("td2");td2.innerHTML=td1.innerHTML;functionhs1(){if(td1.offsetWidth<=div.scrollLeft){div.scrollLeft=0;}else{div.scrollLeft++;}}varid=setInterval(hs1,10);functionhs2(){addEventHandler(div,"mouseover",function(){clearInterval(id);});//使用事件監聽的方法,如果此方法只被調用一次,就可以直接寫在這裡的函數段裡addEventHandler(div,"mouseout",function(){id=setInterval(hs1,10);});}hs2();function addEventHandler(target,type,func){if (target.addEventListener){target.addEventListener(type,func,false);}else if (target.attachEvent){target.attachEvent("on"+type,func);}else{target["on"+type]=func;}}//事件監聽(對於事件監聽的理解在《詳解tab切換四種方法》中有註解)</script>
一 步步實現了無縫迴圈滾動以及監聽使用者動作停止繼續後,就要繼續考慮另一種效果了,當圖片滾動到一定位置時會自動停止,停止多久後再繼續執行正常滾動,使用者 滑鼠放上時也會停止,離開時繼續。這樣的效果我們都能聯想到的就是先命令div的scrollLeft進行到什麼位置後清掉計時器,在使用 setTimeout的計時器控制其再隔多久繼續進行滾動。那麼,我們如何才能擷取到每隔多長的距離才讓其停止呢,注意是“每”我原來試過用加法,顯然是 行不通的,一輪一輪的無限迴圈要加到什麼時候。但是我們同學便想到了一個很巧妙的辦法,求餘。求餘的運算子號是%,求餘也就是擷取倍數,就能實現每前進多 遠就清掉計時器的辦法。代碼解析請看下方代碼:
<script type="text/javascript">vardiv=document.getElementById("div");vartd1=document.getElementById("td1");vartd2=document.getElementById("td2");td2.innerHTML=td1.innerHTML;varidd=null;//此處聲明計時器idd,否則在未讀取對象就有執行關於其的命令時報錯沒有對象。function hs1(){if (td1.offsetWidth<=div.scrollLeft){div.scrollLeft=0;}else{div.scrollLeft++;}if (div.scrollLeft%160==0){//這裡便是求餘的判斷,每當到div的scrollLeft能整除160這個數值的位置時,(數值我們可以自己設),clearInterval(id);//就清掉計時器。idd=setTimeout("id=setInterval(hs1,10)",1000);//setTimeout的計時器,控制停止過一秒時繼續執行計時器id,也就是繼續滾動}}var id=setInterval(hs1,10);function hs2(){addEventHandler(div,"mouseover",function(){if(idd){clearTimeout(idd);}clearInterval(id);});//使用者滑鼠放上時便又要多一句判斷,如果正在運行idd計時器時也將其清掉。addEventHandler(div,"mouseout",function(){id=setInterval(hs1,10);});}hs2();function addEventHandler(target,type,func){if (target.addEventListener){target.addEventListener(type,func,false);}else if (target.attachEvent){target.attachEvent("on"+type,func);}else{target["on"+type]=func;}}//事件監聽</script>
完全圖解scrollLeft,scrollWidth,clientWidth,offsetWidth