空间坐标 视口与文档 首先理解视口(窗口)与文档的含义
网页很多都是多屏(通过滚动条显示看不见的内容),所以文档尺寸一般大于视口尺寸
视口可以理解为可视区域,而不是全部的文档
视口尺寸不包括浏览器工具条、菜单、标签、状态栏等
当你打开控制台后,视口尺寸就相应变小了
position使用文档定位,fixed使用视口定位
文档坐标在页面滚动时不发生改变
视口坐标的操作需要考虑滚动条的位置
视口与文档尺寸 视口坐标需要知道滚动条位置才可以进行计算,有以下几种方式获取滚动位置
方法
说明
注意
window.innerWidth
视口宽度
包括滚动条(不常用)
window.innerHeight
视口高度
包括滚动条(不常用)
document.documentElement.clientWidth
视口宽度
document.documentElement.clientHeight
视口高度
几何尺寸 元素在页面中拥有多个描述几何数值的尺寸,下面截图进行了形象的描述。
方法列表 下面是获取尺寸的方法或属性
方法
说明
备注
element.getBoundingClientRect
返回元素在视口坐标及元素大小,width/height不包括外边距,与offsetWidth/offsetHeight匹配
窗口坐标
element.getClientRects
行级元素每行尺寸位置组成的数组
element.offsetParent
拥有定位属性的父级,或body/td/th/table
对于隐藏元素/body/html值为null
element.offsetWidth
元素宽度尺寸,包括内边距与边框和滚动条
element.offsetHeight
元素高度尺寸,包括内边距与边框和滚动条
element.offsetLeft
相对于祖先元素的X轴坐标
element.offsetTop
相对于祖先元素的Y轴坐标
element.clientWidth
元素宽度,不包含边框,只包含内容和内边距,行元素尺寸为0
element.clientHeight
元素高度,不包含边框,只包含内容和内边距,行元素尺寸为0
element.clientLeft
内容距离外部的距离,滚动条在左侧时包括滚动条尺寸
element.clientTop
内容距离顶部的距离,滚动条在顶部时包括滚动条尺寸
element.scrollWidth
元素宽度,内容+内边距+内容溢出的尺寸
element.scrollHeight
元素高度,内容+内边距+内容溢出的尺寸
element.scrollLeft
水平滚动条左侧已经滚动的宽度
element.scrollTop
垂直滚动条顶部已经滚动的高度
getComputedStyle 为什么不要使用getComputedStyle
尺寸设置auto时获取结果不可用
由于滚动条的存在,不同浏览器返回结果不同
当元素没有设置CSS尺寸时,获取不到相应的尺寸内容
getBoundingClientRect 使用getBoundingClientRect
获取元素矩形信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <style> div { height: 300px; width: 300px; padding: 10px; margin: 10px; border: 5px solid #ddd; overflow: hidden; } </style> <body> <div></div> </body> <script> let div = document.querySelector("div"); let position = div.getBoundingClientRect(); console.log(position); </script>
计算结果的矩形尺寸不包括外边距
1 2 3 4 5 6 7 8 bottom: 340 height: 330 left: 18 right: 348 top: 10 width: 330 x: 18 y: 10
getClientRects getClientRects使用场景:多行元素时 分别返回每行所占的尺寸,下面的行元素将为每行返回对应矩形尺寸
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <style> span { width: 200px; overflow: auto; } </style> <span> 网页很多都是多屏,所以文档尺寸一般大于视口尺寸,当打开控制台后,视口尺寸相应变小。网页很多都是多屏,所以文档尺寸一般大于视口尺寸,当打开控制台后,视口尺寸相应变小。网页很多都是多屏,所以文档尺寸一般大于视口尺寸,当打开控制台后,视口尺寸相应变小。 </span> <script> let span = document.querySelector('span') let info = span.getClientRects() console.log(info) </script>
上例计算结果如下
(index)
x
y
width
height
top
right
bottom
left
值
0
8
8
1255.7125244140625
20.80000114440918
8
1263.7125244140625
28.80000114440918
8
1
8
28.80000114440918
675.8624877929688
20.80000114440918
28.80000114440918
683.8624877929688
49.60000228881836
8
length
2
坐标点元素 JS提供了方法获取指定坐标上的元素,如果指定坐标点在视口外,返回值为NULL
坐标都是从左上角计算,这与CSS中的right/bottom等不同
视口坐标类似于position:fixed
文档坐标类似于position:absolute
方法
说明
element.elementsFromPoint(x,y)
返回指定坐标点所在的元素集合Array
element.elementFromPoint(x,y)
返回指定坐标点最顶层的元素
元素集合 返回指定坐标点上的元素集合Array
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <style> * { margin: 0; padding: 0; } div { background-color: black; width: 100px; height: 100px; } </style> <div id="app"></div> <script> console.log(document.elementsFromPoint(99, 99)); </script>
返回结果为
底层元素 返回坐标点上的最底层的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <style> * { margin: 0; padding: 0; } div { background-color: black; width: 100px; height: 100px; } </style> <div id="app"></div> <script> console.log(document.elementFromPoint(99, 99)); </script>
返回结果为
滚动控制 下面掌握文档或元素的滚动操作
方法列表 获取滚动
方法
说明
参数说明
window.pageXOffset
文档相对视口水平滚动的像素距离
window.pageYOffset
文档相对视口竖直滚动的像素距离
element.scrollLeft
获取和设置元素X轴滚动位置
element.scrollTop
获取和设置元素Y轴滚动位置
控制滚动
方法
说明
说明
element.scrollBy()
按偏移量进行滚动内容
参数为obj
,{top:垂直偏移量,left:水平偏移量,behavior:’滚动方式’}
element.scroll() 或 element.scrollTo()
滚动到指定的具体位置
参数为obj
,{top:X轴文档位置,left:Y轴文档位置,behavior:’滚动方式’}
element.scrollIntoView(bool)
定位到顶部或底部
参数为:obj/boolean
—参数为boolean
:true元素定位到顶部,为false定位到窗口底部。—参数为obj
:{block:"start/end",behavior:"smooth"}
获取滚动位置 文档滚动位置 下例是查看文档滚动的X/Y坐标示例,window.pageXOffset/pageYOffset
1 2 3 4 5 6 7 <div style="width: 3000px; height: 3000px; background: #e34334"></div> <script> window.onscroll = function () { console.log(window.pageXOffset) console.log(window.pageYOffset) } </script>
doucment.documentElement
能够访问到html元素,所以可以使用元素的方法element.scrollTop/scrollLeft
获取
1 2 3 4 5 6 7 <div style="width: 3000px; height: 3000px; background: #e34334"></div> <script> window.onscroll = function () { console.log(document.documentElement.scrollTop) console.log(document.documentElement.scrollLeft) } </script>
元素滚动位置 下面查看元素内容的滚动属性,请在控制台查看结果
要为父元素设置 overflow:scroll 以使其产生滚动条
使用scroll 事件来监听结果
1 2 3 4 5 6 7 8 9 10 <div id="app" style="width: 300px; height: 300px; border: solid 6px #e34334; overflow: auto"> <div style="width: 1000px; height: 1000px; background: #833ca4"></div> </div> <script> const app = document.getElementById('app') app.addEventListener('scroll', function () { console.log(this.scrollLeft) console.log(this.scrollTop) }) </script>
控制滚动位置 下面介绍的是控制元素滚动的操作方法
使用scrollBy({top,left,behavior})
按偏移量 滚动整个文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <style> body { height: 2000px; background: linear-gradient( to bottom, #ecf0f1, #1abc9c, #f39c12, #ecf0f1 ); } </style> <script type="module"> //每隔1秒,向下滚动30px,参照上次的位置,即按偏移量进行滚动 setInterval(() => { document.documentElement.scrollBy({ top: 30, behavior: 'smooth' }) }, 1000) </script>
使用scrollTop/scrollLeft
实现
1 2 3 4 5 6 …… let top = 0; setInterval(() => { top += 30; document.documentElement.scrollTop = top; }, 1000);
使用scroll({top,left,behavior})
滚动到指定位置
1 2 3 4 5 6 7 8 9 10 11 12 <style> body { height: 3000px; } </style> <script type="module"> //3秒后,滚动到指定位置 setTimeout(() => { document.documentElement.scroll({ top: 30, behavior: 'smooth' }) }, 1000) </script>
使用scrollTop/scrollLeft
实现
1 2 3 4 …… setTimeout(() => { document.documentElement.scrollTop = 30; }, 1000);
使用元素scrollIntoView方法实现滚动操作,参数可以是布尔值或对象
参数为Boolean
参数为 true 时顶部对齐,相当于{block: “start”}
参数为 false 时底部对齐,相当于{block: “end”}
参数为obj
block:”start/width”
behavior:”smooth”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <style> div { height: 2000px; background: red; border-top: solid 50px #efbc0f; border-bottom: solid 50px #1bb491; } span { border-radius: 50%; color: #fff; background: #000; width: 50px; height: 50px; display: block; text-align: center; line-height: 50px; position: fixed; top: 50%; right: 50px; border: solid 2px #ddd; } </style> <div id="app">hdcms.com</div> <span>TOP</span> <script> document.querySelector('span').addEventListener('click', () => { let app = document.querySelector('#app') app.scrollIntoView({ block: 'end', behavior: 'smooth' }) }) </script>
案例应用 backTop 下例是开发中常用的回到顶部示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <style> body { height: 2000px; background: linear-gradient( to bottom, #ecf0f1, #1abc9c, #f39c12, #ecf0f1 ); } .backtop { width: 50px; height: 50px; position: fixed; right: 10px; bottom: 10px; z-index: 1; display: flex; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.75); color: white; border-radius: 50%; transition: 0.6s; transform: scale(0); } .show { transform: scale(1) rotateZ(360deg); } </style> <body> <div class="backtop">Top</div> </body> <script> let backtop = document.querySelector(".backtop"); backtop.addEventListener("click", () => { document.documentElement.scrollIntoView({ block: "start", behavior: "smooth", }); }); window.onscroll = function () { let test = document.documentElement.scrollTop + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300; backtop.classList[test ? "add" : "remove"]("show"); }; </script>
漂浮广告 下面是全屏漂浮广告的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 <style> div { border-radius: 10px; text-align: center; color: rgba(255, 255, 255, 0.8); width: 200px; height: 200px; background-color: #e34334; } </style> <body> <div id="app">阿顺特烦恼</div> </body> <script> class Ad { constructor(preset) { this.$el = preset.el; //初始移动方向,1向下/向右 -1 向上/向左 this.x = this.y = 1; this.preset = Object.assign({delay: 10,step: 1,},preset); this.run(); } run() { this.init(); setInterval(() => { this.$el.style.left = this.leftMove() + "px"; this.$el.style.top = this.topMove() + "px"; }, this.preset.delay); } //设置定位模式 init() { this.$el.style.position = "fixed"; this.$el.style.top = 0; this.$el.style.left = 0; } leftMove() { let { x, width } = this.$el.getBoundingClientRect(); let { clientWidth } = document.documentElement; if (x > clientWidth - width) this.x = -1; if (x < 0) this.x = 1; return x + this.preset.step * this.x; } topMove() { let { y, height } = this.$el.getBoundingClientRect(); let { clientHeight } = document.documentElement; if (y > clientHeight - height) this.y = -1; if (y < 0) this.y = 1; return y + this.preset.step * this.y; } } let div = document.querySelector("div"); new Ad({ el: div }); </script>