网站首页 > 技术文章 正文
本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
文档坐标和视口坐标:
元素的位置是以像素来度量的,向右代表x坐标的增加,向下代表y坐标的增加;但是,有两个不同的点作为坐标系的原点:元素的x和y坐标可以相对于文档的左上角或者相对于视口的左上角,也就是对于一个元素来说,会有两种坐标:文档坐标和视口坐标;视口坐标也被称为窗口坐标;
在顶级窗口或标签页中,视口只是实际显示文档内容的浏览器的一部分,它不包括浏览器其他组件,如菜单、工具条等;
对于在框架中显示的文档,视口是定义了框架页的<iframe>元素;
元素大小:
以下的属性和方法不属于DOM2级样式规范,但却与HTML元素的样式息息相关;IE率先引用了一些属性,目前,所有主流的浏览器都支持以下属性;
1. 偏移量(offset dimension):
包括元素在屏幕上占用的所有可见的空间;元素的可见大小包括宽高,所有内边距,滚动条和边框的大小(不包括外边距);
通过以下4个属性可以取得元素的偏移量:
- offsetWidth:元素在水平方向占用的空间大小,以像素计,包括元素的宽度,(可见的)垂直滚动条的宽度,左右边框宽度;
- offsetHeight:元素在垂直方向占用的空间大小,以像素计,包括元素的高度,(可见的)水平滚动条的高度,上下边框高度;
- offsetLeft:元素的左外边框到包含元素的左内边框之间的像素距离,即元素的x坐标;
- offsetTop:元素的上外边框到包含元素的上内边框之间的像素距离,即元素的y坐标;
var mydiv = document.getElementById("mydiv");
console.log(mydiv.offsetWidth);
console.log(mydiv.offsetHeight);
console.log(mydiv.offsetLeft);
console.log(mydiv.offsetTop);
offsetLeft和offsetTop返回值与包含元素有关,对于有些元素,这些值是文档坐标,但对于已定位元素的后代元素和一些其他元素(如表格单元格),这些属性返回的坐标是相对于祖先元素而不是文档;
offsetParent属性:包含元素的引用,也就是相对的父元素;offsetParent不一定与parentNode的值相等;如:<td>元素的offsetParent是作为其祖先元素的<table>元素,因为<table>是在DOM层次中距<td>最近的一个具有大小的元素;
如果其offsetParent属性为null,以上的属性都是文档坐标;
console.log(mydiv.offsetParent);
如果要想知道某个元素在页面上的偏移量,将这个元素的offsetLeft和offsetTop与其offsetParent的相同属性相加,如此循环直至根元素,就可以得到一个基本准确的值;
<style>
*{margin: 0; padding: 0;}
ul,li{list-style: none;}
#container{width: 500px; height:100px; position: absolute;left:50px;top:100px;border:10px solid;background-color: blue;}
#content{width: 400px; height:50px; position: relative; padding-left: 50px;background-color: red; }
#myul{width: 300px; position: relative; background-color: purple;}
#myli{width: 200px; margin-left:20px; background-color: pink;}
</style>
<body>
<div id="container">
<div id="content">
<ul id="myul">
<li id="myli">零点程序员</li>
</ul>
</div>
</div>
<script>
var myli = document.getElementById("myli");
console.log(myli.offsetWidth);
console.log(myli.offsetLeft);
console.log(myli.offsetParent);
var myul = document.getElementById("myul");
console.log(myul.offsetWidth);
console.log(myul.offsetLeft);
console.log(myul.offsetParent);
var content = document.getElementById("content");
console.log(content.offsetWidth);
console.log(content.offsetLeft);
console.log(content.offsetParent);
var container = document.getElementById("container");
console.log(container.offsetWidth);
console.log(container.offsetLeft);
console.log(container.offsetParent);
// 定义一个函数
function getElementPosition(element){
var x = 0, y = 0;
while(element != null){
x += element.offsetLeft;
y += element.offsetTop;
element = element.offsetParent;
}
return {x:x, y:y};
}
var content = document.getElementById("content");
console.log(getElementPosition(content).x);
console.log(getElementPosition(content).y);
var myli = document.getElementById("myli");
console.log(getElementPosition(myli).x);
console.log(getElementPosition(myli).y);
</script>
但实际上这个函数返回的值是不正确的,因为没有包括边框的宽度;
既然offsetWidth和offsetHeight是包括border的宽度的,所以有些地方也把它称为物理宽度,它的值就是该元素实际的尺寸,因此,这并不一定等于元素的width和height,只有元素的CSS设置了box-sizing:border-box时才相等;
对于一个元素来说,它的实际的宽高也并不一定等于它的内容的宽和高,也就是在拥有滚动条的情况下,如:
<style>
#mydiv{width: 300px; height: 100px;border: 1px solid; overflow: scroll;}
</style>
<div id="mydiv">Lorem more...</div>
<script>
var mydiv = document.getElementById("mydiv");
console.log(mydiv.offsetWidth); // 302
console.log(mydiv.offsetHeight); // 102
console.log(mydiv.scrollWidth); // 283
console.log(mydiv.scrollHeight); // 483
</script>
另外,这两个属性值也不包含元素的:before或:after等伪类的宽和高;
<style>
#mydiv{width: 300px; height: 100px;border: 1px solid;}
#mydiv::after{content: "web前端开发"; display: block; margin-top:100px;}
</style>
<div id="mydiv"></div>
<script>
var mydiv = document.getElementById("mydiv");
console.log(mydiv.offsetWidth); // 302
console.log(mydiv.offsetHeight); // 102
</script>
如果该元素的display:none,各属性返回0,offsetParent返回null;
如果该元素的position为static或fixed,其offsetParent为null,此时返回的各个属性值就是文档坐标;
对于行盒元素(如 span),offsetTop和offsetLeft描述的是第一个边界框的位置,offsetWidth和 offsetHeight描述的是边界框的尺寸;因此,使用offsetLeft、offsetTop、offsetWidth、offsetHeight来对应left、top、width和height 的一个盒子将不会是文本容器 span 的盒子边界;如:
<div style="width: 300px; border:1px solid blue;">
<span style="background-color: purple;">span element</span>
<span id="long">Lorem ... text more...</span>
</div>
<div id="box" style="position: absolute; border: 1px solid red; z-index: 10"></div>
<script>
var box = document.getElementById("box");
var long = document.getElementById("long");
box.style.left = long.offsetLeft + "px";
box.style.top = long.offsetTop + "px";
box.style.width = long.offsetWidth + "px";
box.style.height = long.offsetHeight + "px";
</script>
所有这些偏移量属性都是只读的,且每次访问它们都需要重新计算;因此,应该尽量避免重复访问这些属性;如果要使用,可以将它们保存在局部变量中,以提高性能;
myul.offsetLeft = 20;
console.log(myul.offsetLeft); // 50 静默失败
2.客户区大小(client dimension):
指的是元素内容及其内边距所占据的空间大小,相关属性为:clientTop、clientLeft、clientWidth和clientHeight;
客户区大小就是元素内部的空间大小,其与offsetWidth和offsetHeight类似,只不过不包含边框大小;也不包括滚动条占用的空间;
clientWidth = CSS width + CSS padding - 水平滚动条宽度 – CSS border(如果width不包括border的话);
clientHeight = CSS height + CSS padding - 水平滚动条高度 – CSS border(如果height不包括border的话);
var mydiv = document.getElementById("mydiv");
console.log(mydiv.clientWidth);
console.log(mydiv.clientHeight);
注意,它不是元素内容实际的尺寸,而是元素内部可见区域的大小;并且是不包括滚动条的,如:
<style>
#mydiv{width: 300px; height: 100px;padding: ;border: 1px solid; overflow: scroll;}
</style>
<div id="mydiv">Lorem more...</div>
<script>
var mydiv = document.getElementById("mydiv");
console.log(mydiv.offsetWidth); // 302
console.log(mydiv.offsetHeight); // 102
console.log(mydiv.clientWidth); // 300
console.log(mydiv.clientHeight); // 100
console.log(mydiv.scrollWidth); // 300
console.log(mydiv.scrollHeight); // 147
注意:对于行盒,如<i>、<code>或<span>等,包括块盒被设置了display:block后,clientWidth和clientHeight总是返回0;
当元素的display:none时,返回的也是0;
var span = document.getElementsByTagName("span")[0];
console.log(span.clientWidth); // 0
console.log(span.clientHeight); // 0
最典型的应用就是之前讲到的获得浏览器视口大小,如:
function getViewPort(){
if(document.compatMode == "BackCompat"){
return{
width:document.body.clientWidth,
height:document.body.clientHeight
};
}else{
return {
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
};
}
}
有一个特例:在文档的根元素上使用这些属性时,它们的返回值和窗口的innerWidth和innerHeight属性值相等;但如果有滚动条的话,innerWidth和innerHeight包括滚动条占用空间的值;
console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
console.log(window.innerWidth, window.innerHeight);
获得浏览器视口大小:
function getViewportSize(w){
// 使用指定的窗口,如果不带参数则使用当前窗口
w = w || window;
if(w.innerWidth != null) return {w: w.innerWidth, h: w.innerHeight};
var d = w.document;
if(document.compatMode == "CSS1Compat")
return {w: d.documentElement.clientWidth, h: d.documentElement.clientHeight};
// 怪异模式
return {w: d.body.clientWidth, h: d.body.clientHeight};
}
console.log(getViewportSize().h);
与偏移量相似,这两个属性该也为只读,并且每次访问都要重新计算;
clientTop属性和clientLeft属性:可以返回元素的上边框和左边框的大小,其值为一个整数,没有单位,并且是只读的;
var mydiv = document.getElementById("mydiv");
console.log(mydiv.clientTop); // 1
console.log(mydiv.clientLeft); // 1
其和getComputedStyle ()方法的borderTopWidth属性存在一定的区别;
var mydiv = document.getElementById("mydiv");
console.log(mydiv.clientTop); // 12
console.log(getComputedStyle(mydiv,null).borderTopWidth); // 11.5px
可见,clientTop和clientLeft返回的是整数并且没有单位,而borderTopWidth返回的是mydiv的上边框的厚度,是精确的;两者之间的关系是:
mydiv.clientTop = Math.round(parseFloat(getComputedStyle(mydiv,null).borderTopWidth));
但firefox是向下取整;
如果元素有滚动条,并且将这些滚动条放在左侧或顶部,clientLeft和clientTop也就包含了滚动条的宽度;
对于行盒元素来说,clientLeft和clientTop值总是为0;当元素的display:none时,返回的也是0;
3.滚动大小(scroll dimension):
指的是包含滚动内容的元素大小;
有些元素(如<html>),即使没有执行任何代码也能自动地添加滚动条;但另外一些元素,则需要通过css的overflow属性进行设置才能滚动;
滚动相关的属性:
- scrollHeight:在没有滚动条的情况下,元素内容的总高度;
- scrollWidth:在没有滚动条的情况下,元素内容的总宽度;(这两个属性前面用过了)
- scrollLeft:被隐藏在内容区域左侧的像素数;通过设置该属性可以改变元素的滚动位置;
- scrollTop:被隐藏在内容区域上方的像素数;通过设置这个属性可以改变元素的滚动位置;
scrollWidth和scrollHeight主要用于确定元素内容的实际大小,它们是只读的,不包括边框和滚动条;
也就是说,返回的是元素的内容区域加上它的内边距再加上任何溢出内容的尺寸;
<style>
#mydiv{width: 300px;height:100px; border: 1px solid; overflow: scroll;}
</style>
<div id="mydiv">Lorem more...</div>
<script>
var mydiv = document.getElementById("mydiv");
// 283 = 300 -17(滚动条的宽), 168 = 内容实际的高
console.log(mydiv.scrollWidth, mydiv.scrollHeight);
</script>
当内容正好和内容区域匹配而没有溢出时,这些属性与clientWidth与clientHeight是相等的;但当溢出时,它们就包含溢出的内容,返回值比clientWidth和clientHeight要大;
// 改变文字数量,观察两者的区别
console.log(mydiv.scrollWidth, mydiv.scrollHeight);
console.log(mydiv.clientWidth, mydiv.clientHeight);
通常认为<html>(混杂模式下为<body>)元素是在浏览器视口滚动的元素,因此带有垂直滚动条的页面总高度就是document.documentElement.scrollHeight;
对于不包含滚动条的页面,scrollWidth、scrollHeight和clientWidth、clientHeight之间的关系基本是相等的;
console.log(document.documentElement.scrollWidth, document.documentElement.scrollHeight);
console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
scrollWidth和scrollHeight等于文档内容区域的大小,而clientWidth和clientHeight等于视口大小;但低版本的浏览器有可能结果并不一致;
在确定文档的总高度时,必须取得scrollWidth/clientWidth和scrollheight/clientHeight中的最大值,才能保证在跨浏览器的环境下得到精确的结果;
var docWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth);
var docHeight = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight);
注:对于混杂混式下,需要使用document.body
scrollLeft和scrollTop属性:
通过这两个属性可以取得元素当前滚动的状态,也就是滚动位置;它们是可写的,即能设置元素的滚动位置;
scrollLeft 属性可以获取或设置一个元素的内容水平滚动的像素数;scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数;
在尚未滚动时,两值均为0;如果垂直滚动,该值大于0,且表示元素上方不可见内容的像素高度,如果水平滚动,该值大于0,且表示元素左方不可见内容的像素宽;
console.log(document.documentElement.scrollLeft);
console.log(document.documentElement.scrollTop);
示例:滚动一个元素;
<style>
#mydiv{width: 300px; height:100px; border: 2px solid; overflow: scroll hidden; white-space: nowrap;}
</style>
<div id="mydiv">Lorem, more...</div>
<button id="btn">滚</button>
<script>
var mydiv = document.getElementById("mydiv");
var btn = document.getElementById("btn");
btn.onclick = function(e){
mydiv.scrollLeft += 20;
}
</script>
将元素的这两个属性设置为0,就可以重置元素的滚动位置;
function scrollToTop(element){
if(element.scrollTop != 0){
element.scrollTop = 0;
}
}
// 应用
var btn = document.getElementById("btn");
btn.onclick = function(){
scrollToTop(document.documentElement);
}
判定元素是否滚动到底:如果元素滚动到底,下面等式返回true,否则返回false,如:element.scrollHeight - element.scrollTop === element.clientHeight;
var mydiv = document.getElementById("mydiv");
var timer = setInterval(scrollDiv, 100);
function scrollDiv(){
if(mydiv.scrollHeight - mydiv.scrollTop === mydiv.clientHeight)
clearInterval(timer);
else
mydiv.scrollTop += 5;
console.log("scroll");
}
检查容器能否滚动:
// 加个判断,条件也可以是:
// window.getComputedStyle(mydiv).overflow === 'hidden'
var timer;
if(window.getComputedStyle(mydiv).overflowY === 'scroll'){
timer = setInterval(scrollDiv, 100);
}
scrollLeft和scrollTop可以被设置为任何整数值,但有以下特点:
- 如果一个元素不能被滚动(例如,它没有溢出),scrollTop将被设置为0;
- 设置的值小于0,这两个属性值被设为0;
- 如果设置了超出这个容器可滚动的值,,这两个属性会被设为最大值;
var mydiv = document.getElementById("mydiv");
mydiv.scrollTop = 500; // 或设为负数
console.log(mydiv.scrollTop); // 0
这两个属性值有可能是小数(比如缩放了页面的显示大小),所以在取值时最好取整,例如:Math.ceil()或Math.floor;
function getElementPos(element){
var y = 0, x = 0;
var current = element;
for(var e = element; e != null; e = e.offsetParent){
// 但是自己的边框不能加进去
if(current == e){
x += e.offsetLeft;
y += e.offsetTop;
}else{
x += e.offsetLeft + e.clientLeft;
y += e.offsetTop + e.clientTop;
}
}
// 再次循环所有的祖先元素,减去滚动的偏移量,并转换为视口坐标
for(var e=element.parentNode; e != null && e.nodeType == 1; e = e.parentNode){
y -= e.scrollTop;
x -= e.scrollLeft;
}
return {x:x, y:y};
}
var mydiv = document.getElementById("mydiv");
console.log(getElementPos(mydiv).x);
console.log(getElementPos(mydiv).y);
console.log(mydiv.offsetParent);
console.log(mydiv.getBoundingClientRect());
示例:返回到顶部:
var gotop = document.getElementById("gotop");
var timer;
gotop.onclick = function(){
timer = setInterval(goTop, 1);
}
function goTop(){
if(document.documentElement.scrollTop == 0)
clearInterval(timer);
else{
// document.documentElement.scrollTop-= 10;
document.documentElement.scrollTop-= document.documentElement.scrollTop / 100;
}
}
// 或者使用递归
gotop.onclick = goTop;
function goTop(){
console.log("a:" + document.documentElement.scrollTop);
if(document.documentElement.scrollTop == 0)
return;
document.documentElement.scrollTop -= 10;
setTimeout(goTop,1);
}
示例:判定用户是否阅读过文本,如:
<style>
.registration{
width: 600px; height: 200px; padding: 10px;
border: 2px solid purple; border-radius: 5px;
overflow-y: scroll;
}
</style>
<h1>同意协议</h1>
<div class="registration">
<p>Lorem more...</p>
</div>
<p>
<input type="checkbox" name="accept" id="agree" />
<label for="agree">我同意</label>
<input type="submit" id="nextstep" value="下一步" />
</p>
<script>
window.onload = function(){
var registration = document.querySelector(".registration");
var agree = document.getElementById("agree");
agree.disabled = true;
var nextstep = document.getElementById("nextstep");
nextstep.disabled = true;
var readed = false;
var noticeBox = document.createElement("h2");
noticeBox.id = "notice";
noticeBox.innerText = "请阅读以下内容"
registration.parentNode.insertBefore(noticeBox, registration);
registration.onscroll = function(e){
if(readed) return;
readed = this.scrollHeight - this.scrollTop === this.clientHeight;
agree.disabled = nextstep.disabled = !readed;
noticeBox.innerText = readed ? "欢迎参加" : "请继续阅读";
}
}
</script>
示例:滚动文本,如:
<style>
*{margin: 0; padding: 0;}
#scrollBox{padding:10px;margin:100px auto;width: 300px; height: 150px; background: lightgray;overflow: hidden;}
</style>
<div id="scrollBox">
<ul id="con1">
<li>HTML</li>
<li>CSS</li>
<li>Javascript</li>
<li>更多的li</li>
<li>更多的li</li>
<li>更多的li</li>
<li>更多的li</li>
<li>更多的li</li>
</ul>
<ul id="con2"></ul>
</div>
<script>
var scrollBox = document.getElementById("scrollBox");
var con1 = document.getElementById("con1");
var con2 = document.getElementById("con2");
con2.innerHTML = con1.innerHTML;
function scrollUp(){
if(scrollBox.scrollTop >= con1.offsetHeight)
scrollBox.scrollTop = 0;
else
scrollBox.scrollTop++;
}
var timer = setInterval(scrollUp, 50);
scrollBox.onmouseover = function(){
clearInterval(timer);
};
scrollBox.onmouseout = function(){
timer = setInterval(scrollUp, 50);
}
</script>
图示汇总各个属性:
windows对象的pageXOffset、pageYOffset和scrollX、scrollY:
pageXOffset 和 pageYOffset 属性返回文档在窗口左上角水平和垂直方向滚动的像素;这一对属性等于scrollX和scrollY属性,前者是后者的别称;但IE不支持后者;这些属性是只读的;
window.scrollBy(100,200);
console.log(window.pageXOffset);
console.log(window.pageYOffset);
console.log(window.scrollX);
console.log(window.scrollY);
console.log(window.pageXOffset == window.scrollX); // true
与scrollLeft和scrollTop关系:返回值是一样的;
window.scroll(100,300);
console.log(window.pageXOffset);
console.log(window.pageYOffset);
console.log(document.documentElement.scrollLeft);
console.log(document.documentElement.scrollTop);
为了跨浏览器兼容性,一般使用window.pageXOffset代替window.scrollX;另外,旧版本的 IE(<9)两个属性都不支持,必须通过其他的非标准属性来解决此问题;
window.scrollBy(100,200);
var x = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
var y = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
console.log(x,y);
// 或者
var isCSS1Compat = document.compatMode === "CSS1Compat";
var x = window.pageXOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
var y = window.pageXOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
console.log(x,y);
封装一个函数:
// 以一个对象的x和y属性的方式返回滚动条的偏移量
function getScrollOffset(w){
// 使用指定的窗口,如果不带参数则使用当前窗口
w = w || window;
if(w.pageXOffset != null) return {x: w.pageXOffset, y: w.pageYOffset};
var d = w.document;
if(document.compatMode == "CSS1Compat")
return {x: d.documentElement.scrollLeft, y: d.documentElement.scrollTop};
// 针对怪异模式
return {x: d.body.scrollLeft, y: d.body.scrollTop};
}
console.log(getScrollOffset().x);
console.log(getScrollOffset().y);
4. 确定元素大小:
浏览器为每个元素都提供了一个Element.getBoundingClientRect()([?ba?nd??] 边界)方法;该方法是在IE5引入的;该方法不需要参数,返回一个矩形对象,类型为DOMRect,包含6个属性:x、y、left、top、right、bottom、width和height;这些属性给出了元素在页面中相对于视口的位置和宽高;其中,x和left相同,y与top相同;right和bottom属性表示元素的右下角的x和y坐标;
<div id="mydiv" style="width: 200px;height:100px;background-color:red; ">id is mydiv</div>
<div style="width: 2000px; background-color: purple;">div</div>
<script>
var mydiv = document.getElementById("mydiv");
var rect = mydiv.getBoundingClientRect();
console.log(rect);
rect = document.documentElement.getBoundingClientRect();
console.log(rect);
</script>
IE并没有实现x和y;
DOMRect 中的 top, left, right, bottom 属性是使用对象的其他属性的值来计算获得的;
在IE及老款的Edge中,该方法返回的并不是DOMRect类型,而是ClientRect类型;
console.log(ClientRect);
console.log(ClientRect.prototype); // [object ClientRectPrototype]
getBoundingClientRect()返回的数据是包括元素的border及padding;
<div id="mydiv" style="width: 200px;height:100px;background-color:red; border:20px solid black;">name is mydiv</div>
// …
var rect = mydiv.getBoundingClientRect();
console.log(rect);
这是标准盒子,如果是怪异盒子,比如在CSS中设置box-sizing:border-box,那么返回的数据中的宽和高就等于元素的width和height;
如果要转化为文档坐标,需要加上滚动的偏移量;
window.scrollBy(50,100);
var mydiv = document.getElementById("mydiv");
var rect = mydiv.getBoundingClientRect();
var x = rect.left + document.documentElement.scrollLeft;
var y = rect.top + document.documentElement.scrollTop;
// 或者使用上面定义的getScrollOffset()函数
var offsets = getScrollOffset();
var x = rect.left + offsets.x;
var y = rect.top + offsets.y;
console.log(x,y);
在布局中,文档中的元素分为块盒和行盒,块盒总是为矩形,但行盒可能跨了多行,因此可能由多个矩形组成,可以把它称为边界矩形;
var span = document.getElementById("mydiv").getElementsByTagName("span")[0];
var rect = span.getBoundingClientRect();
console.log(rect);
在IE8及以下浏览器中,该方法返回的对象中并不包括width和height属性;可以使用一个简便的方式计算元素的width和height属性:
var mydiv = document.getElementById("mydiv");
var rect = mydiv.getBoundingClientRect();
var w = rect.width || (rect.right - rect.left);
var h = rect.height || (rect.bottom - rect.top);
console.log(w,h);
示例:元素在页面上的相对文档的偏移量,如:
function getOffset(ele){
if (!ele || ele.nodeType != 1)
return;
var rect = ele.getBoundingClientRect(),
doc = ele.ownerDocument.documentElement;
return {
top: rect.top + window.pageYOffset - doc.clientTop,
left: rect.left + window.pageXOffset - doc.clientLeft
};
}
getClientRects()方法:
该方法返回一个指向客户端中每一个盒子的边界矩形的矩形集合;该矩形集合是一个只读的类数组对象DOMRectList,可以称为矩形列表对象,它的每个元素都是DOMRect对象;
var span = document.getElementsByTagName("span")[0];
var rects = span.getClientRects();
console.log(rects);
for(var i=0,len=rects.length; i<len; i++){
console.log(rects[i]);
}
当然,该方法也可以应用在块盒中,此时它只返回包含一个元素的集合对象;
var mydiv = document.getElementById("mydiv");
console.log(mydiv.getClientRects()[0]);
在IE中返回的是ClientRectList类型,其中保存的是ClientRect类型的对象;
对于HTML area元素、自身不做任何渲染的SVG元素、display:none元素和不直接渲染出来的任何元素,都将会返回一个空列表;
小示例:
<style>
div{display: inline-block; width: 150px;}
div p,ol,table{border: 1px solid blue;}
span, li, th, td{border: 1px solid green;}
</style>
<div>
<strong>原始</strong>
<p><span>Web前端开发课程,包括HTML、CSS、Javascript等内容</span></p>
</div>
<div>
<strong>p的rect</strong>
<p class="rect"><span>Web前端开发课程,包括HTML、CSS、Javascript等内容</span></p>
</div>
<div>
<strong>span的rect</strong>
<p class="rect"><span>Web前端开发课程,包括HTML、CSS、Javascript等内容</span></p>
</div>
<hr />
<div>
<strong>原始</strong>
<ol>
<li>HTML</li>
<li>CSS</li>
</ol>
</div>
<div>
<strong>ol的rect</strong>
<ol class="rect">
<li>HTML</li>
<li>CSS</li>
</ol>
</div>
<div>
<strong>li的rect</strong>
<ol>
<li class="rect">HTML</li>
<li class="rect">CSS</li>
</ol>
</div>
<hr/>
<div>
<table>
<caption>原始</caption>
<thead><tr><th>thead</th></tr></thead>
<tbody><tr><td>tbody</td></tr></tbody>
</table>
</div>
<div>
<table class="rect">
<caption>table的rect</caption>
<thead><tr><th>thead</th></tr></thead>
<tbody><tr><td>tbody</td></tr></tbody>
</table>
</div>
<div>
<table>
<caption>td的rect</caption>
<thead><tr><th class="rect">thead</th></tr></thead>
<tbody><tr><td class="rect">tbody</td></tr></tbody>
</table>
</div>
<script>
function addClientRect(elt){
// 为了使边框宽度与矩形宽度一致,这里给每个客户矩形上方绝对定位一个 div。
// 注意:如果用户改变大小或者缩放,绘图将会重绘。
var rects = elt.getClientRects();
for(var i=0, len=rects.length; i<len; i++){
var rect = rects[i];
// console.log(rect);
var overlayDiv = document.createElement("div");
overlayDiv.className = "overlay";
overlayDiv.style.position = "absolute";
overlayDiv.style.border = "1px solid red";
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
overlayDiv.style.margin = overlayDiv.style.padding = "0";
overlayDiv.style.top = (rect.top + scrollTop) + "px";
overlayDiv.style.left = (rect.left + scrollLeft) + "px";
// 希望rect.width作为边框宽度,所以内容宽度减少2px
overlayDiv.style.width = (rect.width - 2) + "px";
overlayDiv.style.height = (rect.height - 2) + "px";
document.body.appendChild(overlayDiv);
}
}
var elts = document.querySelectorAll(".rect");
for(var i=0,len=elts.length; i<len; i++)
addClientRect(elts[i]);
</script>
对于NodeList等对象,它们是实时的,但getBoundingClientRect()和getClientRects()所返回的矩形对象或矩形列表对象并不是实时的,它们只是调用方法时文档视觉状态的静态快照,在用户滚动或改变浏览器窗口大小时不会更新它们;
document.elementFromPoint()方法:如果想在指定位置上判定有什么元素,可以使用该方法;参数需要传递x和y坐标,不需要单位px,该坐标是视口坐标,该方法返回在指定位置的一个元素;
如果在指定位置有多个元素,它返回的是里面和最上面的(即CSS的z-index属性),如果指定的点在视口以外,该方法返回null;
典型的案例是将鼠标指针的坐标传递给它来判断鼠标在哪个元素上,但是,在鼠标事件中的target属性也包含了这些坐标信息,所以,elementFromPoint()方法并不常用;
var div = document.createElement("div");
div.id="divone";
div.setAttribute("style","width:200px;height:100px;position:absolute;left:50px;top:200px;border:solid 5px;");
document.documentElement.appendChild(div);
var innerDiv = document.createElement("div");
innerDiv.setAttribute("style","background-color:purple; width:100px; height:50px;");
div.appendChild(innerDiv);
var elt = document.elementFromPoint(100,200);
console.log(elt);
console.log(div.getBoundingClientRect());
// 鼠标事件中的坐标
var mydiv = document.getElementById("mydiv");
document.addEventListener("click",function(e){
console.log(e.target);
console.log(e.clientX, e.clientY);
},false);
document.elementsFromPoint()方法:该方法返还在特定坐标点下的HTML元素数组;IE与老版的Edge并不支持;
var elts = document.elementsFromPoint(100,250);
console.log(elts);
滚动:
Window.scroll()、Window.scrollBy()、Window.scrollTo()及Element.scroll()、Element.scrollBy()、Element.scrollTo();
scroll(x, y)或scrollTo(x, y)方法:
var btn = document.querySelector(".btn");
btn.onclick = function(){
var documentHeight = document.documentElement.offsetHeight;
var viewportHeight = window.innerHeight;
// 滚动到最后一屏
window.scrollTo(0, documentHeight - viewportHeight);
}
scrollBy(x, y)方法:
其与以上两个方法类似,但是它的参数是相对的,并在当前滚动的偏移量上增加
window.scrollBy(5,5);
示例,阅读文章时自动滚屏,如:
<style>
.autoscrollbtn{width: 50px; height: 50px; background-color: purple;
position: fixed; top:100px; right: 100px; color:#FFF}
</style>
<div>lorem</div>
<div class="autoscrollbtn">滚</div>
<script>
// 3874 4531
var btn = document.querySelector(".autoscrollbtn");
var timer;
var viewportHeight = window.innerHeight;
var stop = false;
btn.addEventListener("click",function(e){
if(!stop){
e.target.innerText = "停";
timer = setInterval(function(){
if((viewportHeight + document.documentElement.scrollTop) >=
document.documentElement.offsetHeight)
clearInterval(timer);
scrollBy(0,2);
},200);
}else{
e.target.innerText = "滚";
clearInterval(timer);
}
stop = !stop;
});
</script>
以上方法,参数除了x和y坐标外,还可以是一个ScrollToOptions对象;
CSSOM View 规范的ScrollToOptions对象,用于指定一个元素应该滚动到哪里,以及滚动是否应该平滑;与我们之前讲的scrollIntoView()方法的参数类似,但类型不一样,其为ScrollIntoViewOptions,属性为block及inline等;而ScrollToOptions对象拥有的是top、left和behavior属性,其中behavior属性值可能为:auto及smooth;该参数IE和Edge不支持;
如果不使用ScrollToOptions对象参数,也可以使用CSS指定,如:
html,body{
scroll-behavior:smooth;
}
但IE和Edge依然不支持;
var btn = document.getElementById("btn");
btn.addEventListener("click",function(e){
window.scroll(mydiv.offsetLeft,mydiv.offsetTop);
// 或,但IE与Edge不支持
window.scroll({left:mydiv.offsetLeft, top:mydiv.offsetTop, behavior:"smooth"});
},false);
Element.scroll()、Element.scrollBy()、Element.scrollTo();
这些方法是用于在给定的元素中滚动到某个特定坐标,其用法与window上的三个方法一致,但IE与Edge均不支持Element的方法;
<div id="mydiv" style="background-color: purple; width: 300px; height: 400px; overflow-y: scroll;">Lorem</div>
<script>
var mydiv = document.getElementById("mydiv");
mydiv.scroll(0,300);
</script>
- 上一篇: 禁用qq浏览器数字文本框 鼠标滚轮滑动 数字加减
- 下一篇: 用JS做个自由落体的球
猜你喜欢
- 2024-11-24 六种设计难题的CSS实用技巧
- 2024-11-24 前端入门教程:CSS标准盒模型和怪异盒模型区别
- 2024-11-24 WEB前端-CSS盒子
- 2024-11-24 手把手教你css 中多种边框的实现小窍门【实践】
- 2024-11-24 纯CSS实现轮播图
- 2024-11-24 「干货」移动端Web页面适配
- 2024-11-24 《Web前端技术H5+CSS3》笔记--第六章 盒子模型「云图智联」
- 2024-11-24 深入浅出超好用的 CSS 阴影技巧
- 2024-11-24 掌握Flex布局的这几个常用属性,搞定弹性布局不在话下
- 2024-11-24 用 CSS Grid 布局制作一个响应式柱状图
- 标签列表
-
- content-disposition (47)
- nth-child (56)
- math.pow (44)
- 原型和原型链 (63)
- canvas mdn (36)
- css @media (49)
- promise mdn (39)
- readasdataurl (52)
- if-modified-since (49)
- css ::after (50)
- border-image-slice (40)
- flex mdn (37)
- .join (41)
- function.apply (60)
- input type number (64)
- weakmap (62)
- js arguments (45)
- js delete方法 (61)
- blob type (44)
- math.max.apply (51)
- js (44)
- firefox 3 (47)
- cssbox-sizing (52)
- js删除 (49)
- js for continue (56)
- 最新留言
-