有時候項目中會用到用js獲取元素位置來定位元素,我在網上開了大量的 圖解,代碼,最終把我搞的暈了,仍是結合網上的 本身來總結一下,首先來看看網上的: javascript
DOM的定義以下圖 css
scrollLeft:設置或獲取位於對象左邊界和窗口中目前可見內容的最左端之間的距離
scrollTop:設置或獲取位於對象最頂端和窗口中可見內容的最頂端之間的距離
scrollWidth:獲取對象的滾動寬度
offsetHeight:獲取對象相對於版面或由父座標 offsetParent 屬性指定的父座標的高度
offsetLeft:獲取對象相對於版面或由 offsetParent 屬性指定的父座標的計算左側位置
offsetTop:獲取對象相對於版面或由 offsetTop 屬性指定的父座標的計算頂端位置
event.clientX 相對文檔的水平座標
event.clientY 相對文檔的垂直座標
event.offsetX 相對容器的水平座標
event.offsetY 相對容器的垂直座標
document.documentElement.scrollTop 垂直方向滾動的值 html
獲取元素的位置屬性能夠經過 java
可是,這兩個屬性所儲存的數值並非該元素相對整個瀏覽器畫布的絕對位置,而是相對於其父元素位置的相對位置,也就是說這兩個數值獲得的是以其 父元素左上角爲(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 相對文檔的水平座標+垂直方向滾動的量
上面的紅色部分以經講的很清楚 offsetwidth,如今裏看看 函數
在說說, scrollLeft :設置或獲取位於對象左邊界和窗口中目前可見內容的最左端之間的距離。 spa
在說以前 首先來看一段文字: code
scrollLeft:設置或獲取位於對象左邊界和窗口中目前可見內容的最左端之間的距離。 orm
一、innerHTML:inner(裏面,元素),innerHTML是用來改變對象DH內部的HTML語句。而此效果中咱們所用到的a.innerHTML=b.innerHTML就是b將本身的HTML元素賦予a,用在這裏就如克隆一說。 htm
二、offsetWidth:是指對象包括邊框在內的寬度。與clientWidth不一樣,clientWidth指對象不包括邊框只包括內容的實際寬度。
三、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" alt=""/></a> <a href="#"><img src="images/tu2.jpg" alt=""/></a> <a href="#"><img src="images/tu3.jpg" alt=""/></a> <a href="#"><img src="images/tu4.jpg" alt=""/></a> <a href="#"><img src="images/tu5.jpg" alt=""/></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");//最外層div var td1=document.getElementById("td1");//第一個td,裏面包裹圖片 var td2=document.getElementById("td2");//沒有包裹內容(圖片)的td td2.innerHTML=td1.innerHTML;//將第一個td中的內容賦予第二個td function 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的scrollLeft div.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>