引言
最近突然看到了有關圖片懶載入的問題,大致意思是初始狀態下頁面只載入瀏覽器視覺區域的圖片,剩餘圖片在當瀏覽器可視區域滾動到其位置時才開始載入。看起來現在許多大型網站都有實現懶加載,所以我便就此問題思考了一下。首先第一個問題是瀏覽器沒有相關的 API 方法可以偵測某個元素是否在視覺區域,那麼就只能我們人工計算,所以這裡就涉及到了元素長寬,滾動條位置的知識。本文涉及的到的知識有元素長寬 clientWidth/offsetWidth/scrollWidth 的區別、以及 clientTop/offsetTop/scrollTop 的區別,並給了獲取元素坐標的源代碼。
一、 clientWidth、offsetWidth、scrollWidth 的差異
通常大家取得元素的長寬的時候都會使用一些框架封裝好的方法,例如jQuery.prototype.width() ,這些框架使用起來方便快捷,不過其中涉及到的知識還是非常多的,關於元素的長寬,有多種的獲取方法,其代表的實際意義也是不同的。
簡單來說可以使用下列公式:
clientWidth = width(可視區) + padding
offsetWidth = width(視覺區) + padding + border
# scrollWidth = width(內容區)
# 假設有我們以下一個元素:
1 #test {2 width: 100px;3 height: 100px;4 margin: 10px;5 border: 10px solid #293482;6 padding: 10px;7 background-color: yellow;8 overflow: auto;9 }
![]() |
![]() |
![]() |
![]() | #scrollWidth
## | ||
![]() ## | 以上DEMO 是常規情況下的區別,下面加上一個滾動條我們們再來觀察以下: ![]() |
![]() clientWidth |
![]() | #scrollWidth
二、clientTop、offsetTop、scrollTop 的区别
我们使用以下公式:
clientTop = border
offsetTop = 元素边框外围至父元素边框内围
scrollTop = 元素可视区域顶部至实际内容区域的顶部
给定以下两个元素 container 和 test
1 #container { 2 background-color: #F08D8D; 3 padding: 10px; 4 } 5 #test { 6 position: relative; 7 top: 10px; 8 width: 100px; 9 height: 100px;10 margin: 20px;11 border: 15px solid #293482;12 padding: 10px;13 background-color: yellow;14 }
clientTop | offsetTop | scrollTop |
![]() |
![]() |
![]() |
![]() |
三、获取页面元素绝对定位坐标
有了以上知识基础之后,我们现在需要考虑的问题是,如何获取页面元素的绝对位置,也就是在文档流内容区的位置。我们知道,元素的 offsetTop 属性可以获取当前元素边框外围至父元素边框内围的的距离,clientTop 可以获取元素边框的宽度。那么现在用一个递归的公式就可以求得当前元素在页面中的绝对位置:
Element.absoluteTop = Element.parent.absoluteTop + Element.offsetTop + Element.clientTop;
同理,我们用参照元素的长宽减去 left 和 top 和定位,即可得到 right 和 bottom 的定位;
所以我们可以编写以下工具来获取元素的绝对位置,也就是在内容区的定位(参照元素必须是目标元素的祖先元素):
1 var Position = {}; 2 (function () { 3 Position.getAbsolute = function (reference, target) { 4 //因为我们会将目标元素的边框纳入递归公式中,这里先减去对应的值 5 var result = { 6 left: -target.clientLeft, 7 top: -target.clientTop 8 } 9 var node = target;10 while(node != reference && node != document){11 result.left = result.left + node.offsetLeft + node.clientLeft;12 result.top = result.top + node.offsetTop + node.clientTop;13 node = node.parentNode;14 }15 if(isNaN(reference.scrollLeft)){16 result.right = document.documentElement.scrollWidth - result.left;17 result.bottom = document.documentElement.scrollHeight - result.top;18 }else {19 result.right = reference.scrollWidth - result.left;20 result.bottom = reference.scrollHeight - result.top;21 }22 return result;23 }24 })();
此方法可以获取一个元素相对于一个父元素的定位,如果要获取元素在整张页面,直接传入 document 即可:
1 Position.getAbsolute(document, targetNode); //{left: left, right: right, top: top, bottom: bottom}
四、获取元素的可视区定位坐标
在上一小节中,我们封装了一个函数,这个函数可以用来获取一个元素的相对于一个祖先元素的绝对定位坐标,在这一小节中,我们来获取元素相对于浏览器窗口可视区域的定位坐标。在上一个函数中,我们可以获取一个元素在 document 当中的定位,还记得我们在第二小节中的 scrollTop 属性吗?该属性可以获取滚动窗口可视区域顶端距离内容区顶端的距离,我们用元素的绝对定位坐标减去 document 的滚动定位就是我们想要的浏览器窗口定位啦(相对于浏览器左上角):
ViewportTop = Element.absoluteTop - document.body.scrollTop;
这里需要注意一个兼容性的问题,在 Chrome 中可以用 document.body.scrollTop 和 window.pageYOffset,IE 7/8 只能通过 document.documentElement.scrollTop 获取, FireFox 和 IE9+ 可以用 document.documentElement.scrollTop 和 window.pageYOffset 获取,Safari 需要 window.pageYOffset 获取。所以这里我们需要做一下浏览器兼容:
scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
注意这里的顺序,在 IE7/8 中 window.pageYOffset 是 undefined ,document.body.scrollTop 在任何浏览器中都有,只是不支持的值为 0,如果表达式返回 undefined ,会影响后面的计算操作。而 || 运算符是一个短路取真运算符,所以我们要所有浏览器都有的 document.body.scrollTop 方法放在最后,关于 || 运算符的问题,可以参考 《探寻 JavaScript 逻辑运算符(与、或)的真谛》。
我们在刚才的工具上添加一个方法:
1 var Position = {}; 2 (function () { 3 Position.getAbsolute = function (reference, target) { 4 var result = { 5 left: -target.clientLeft, 6 top: -target.clientTop 7 } 8 var node = target; 9 while(node != reference && node != document){10 result.left = result.left + node.offsetLeft + node.clientLeft;11 result.top = result.top + node.offsetTop + node.clientTop;12 node = node.parentNode;13 }14 if(isNaN(reference.scrollLeft)){15 result.right = document.documentElement.scrollWidth - result.left;16 result.bottom = document.documentElement.scrollHeight - result.top;17 }else {18 result.right = reference.scrollWidth - result.left;19 result.bottom = reference.scrollHeight - result.top;20 }21 return result;22 }23 Position.getViewport = function (target) {24 var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;25 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;26 var absolutePosi = this.getAbsolute(document, target);27 var Viewport = {28 left: absolutePosi.left - scrollLeft,29 top: absolutePosi.top - scrollTop,30 }31 return Viewport;32 }33 })();
通过 Position.getViewport 方法可以获取元素相对于浏览器窗口的定位:
1 Postion.getViewport(targetNode); //{left: left, top: top}
五、判断可视区域
在上面的几个方法中,我们可以获取元素的文档流定位和视窗定位,不过这还是不能判断一个元素是否在可视区域内,因为视窗定位可以是非常大的数字,这样元素就在视窗的后面。这里我们需要使用浏览器视窗高度 window.innerHeight 属性,在 IE8 以下需要用 document.documentElement.clientHeight 来获取。
windowHeight = window.innerHeight || document.documentElement.clientHeight;
现在,我们用窗口的高度,减去相对于浏览器窗口的定位,即可获取相对于浏览器窗口右下角的定位;
1 var Position = {}; 2 (function () { 3 Position.getAbsolute = function (reference, target) { 4 var result = { 5 left: -target.clientLeft, 6 top: -target.clientTop 7 } 8 var node = target; 9 while(node != reference && node != document){10 result.left = result.left + node.offsetLeft + node.clientLeft;11 result.top = result.top + node.offsetTop + node.clientTop;12 node = node.parentNode;13 }14 if(isNaN(reference.scrollLeft)){15 result.right = document.documentElement.scrollWidth - result.left;16 result.bottom = document.documentElement.scrollHeight - result.top;17 }else {18 result.right = reference.scrollWidth - result.left;19 result.bottom = reference.scrollHeight - result.top;20 }21 return result;22 }23 Position.getViewport = function (target) {24 var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;25 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;26 var windowHeight = window.innerHeight || document.documentElement.offsetHeight;27 var windowWidth = window.innerWidth || document.documentElement.offsetWidth;28 var absolutePosi = this.getAbsolute(document, target);29 var Viewport = {30 left: absolutePosi.left - scrollLeft,31 top: absolutePosi.top - scrollTop,32 right: windowWidth - (absolutePosi.left - scrollLeft),33 bottom: windowHeight - (absolutePosi.top - scrollTop)34 }35 return Viewport;36 }37 })();
现在我们使用 Position.getViewport(targetNode) 方法可以获取元素左上角相对于窗口4个方向的定位:
1 Position.getViewport(targetNode); //{left: left, top: top, right: right, bottom: bottom}
有了这个方法,现在就可以真正的判断元素是否在可视区域内了:
1 var Position = {}; 2 (function () { 3 Position.getAbsolute = function (reference, target) { 4 //因为我们会将目标元素的边框纳入递归公式中,这里先减去对应的值 5 var result = { 6 left: -target.clientLeft, 7 top: -target.clientTop 8 } 9 var node = target;10 while(node != reference && node != document){11 result.left = result.left + node.offsetLeft + node.clientLeft;12 result.top = result.top + node.offsetTop + node.clientTop;13 node = node.parentNode;14 }15 if(isNaN(reference.scrollLeft)){16 result.right = document.documentElement.scrollWidth - result.left;17 result.bottom = document.documentElement.scrollHeight - result.top;18 }else {19 result.right = reference.scrollWidth - result.left;20 result.bottom = reference.scrollHeight - result.top;21 }22 return result;23 }24 Position.getViewport = function (target) {25 var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;26 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;27 var windowHeight = window.innerHeight || document.documentElement.offsetHeight;28 var windowWidth = window.innerWidth || document.documentElement.offsetWidth;29 var absolutePosi = this.getAbsolute(document, target);30 var Viewport = {31 left: absolutePosi.left - scrollLeft,32 top: absolutePosi.top - scrollTop,33 right: windowWidth - (absolutePosi.left - scrollLeft),34 bottom: windowHeight - (absolutePosi.top - scrollTop)35 }36 return Viewport;37 }38 Position.isViewport = function (target) {39 var position = this.getViewport(target);40 //这里需要加上元素自身的宽高,因为定位点是元素的左上角41 if(position.left + target.offsetWidth
判断理由很简单,如果有一边的定位是负值,那么元素就不在视窗内。
1 Position.getAbsolute(document, targetNode); //获取元素在文档流中的绝对坐标2 Position.getViewport(targetNode); //获取元素相对于浏览器视窗的坐标3 Position.isViewport(targetNode); //判断元素是否在浏览器视窗内
浏览器兼容性:
Chrome | FireFox | IE | Safari | Edge |
Support | Support | IE8+ Support | Support | Support |
IE7 也可以使用,不过结果可能会有一点差异。
扩展:图片懒加载
在文章的开始,我们提到过图片懒加载的问题,那么具体需要怎么实现呢?这里只是给出一个思路:
初始状态下不设置 img 的 src,将图片的真实 url 缓存在 Img 标签上,我们可以设置为 data-src ,这样图片就不会加载了,随后给鼠标添加 mousescroll 事情,每次鼠标滚动的时候将进入可视区域的图片的 src 还原,这样也就实现了图片懒加载效果。不过初始状态下需要将页面可视区域的图片先加载出来。
参考文献:
阮一峰 — 用 JavaScript 获取元素页面元素位置
张媛媛 — js实现一个图片懒加载插件
以上是JavaScript怎麼才能取得元素的座標的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript在瀏覽器和Node.js環境中運行,依賴JavaScript引擎解析和執行代碼。 1)解析階段生成抽象語法樹(AST);2)編譯階段將AST轉換為字節碼或機器碼;3)執行階段執行編譯後的代碼。

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

Dreamweaver Mac版
視覺化網頁開發工具

WebStorm Mac版
好用的JavaScript開發工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。