完全图解scrollLeft,scrollWidth,clientWidth,offsetWidth 获取相对途径,滚动图片
有时候项目中会用到用js获取元素位置来定位元素,我在网上开了大量的 图解,代码,最终把我搞的晕了,还是结合网上的 自己来总结一下,首先来看看网上的:
DOM的定义如下图
获取元素的位置属性可以通过
- 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),我们可以稍稍改变一下得到一方法
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};
scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离
scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离
scrollWidth:获取对象的滚动宽度
offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度
offsetLeft:获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置
offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置
event.clientX 相对文档的水平座标
event.clientY 相对文档的垂直座标
event.offsetX 相对容器的水平坐标
event.offsetY 相对容器的垂直坐标
document.documentElement.scrollTop 垂直方向滚动的值
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" 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>