目錄
 引言" > 引言
 一、 clientWidth、offsetWidth、scrollWidth 的差異" > 一、 clientWidth、offsetWidth、scrollWidth 的差異
首頁 web前端 js教程 JavaScript怎麼才能取得元素的座標

JavaScript怎麼才能取得元素的座標

Jul 21, 2017 pm 05:08 PM
javascript js 元素

 引言

  最近突然看到了有關圖片懶載入的問題,大致意思是初始狀態下頁面只載入瀏覽器視覺區域的圖片,剩餘圖片在當瀏覽器可視區域滾動到其位置時才開始載入。看起來現在許多大型網站都有實現懶加載,所以我便就此問題思考了一下。首先第一個問題是瀏覽器沒有相關的 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
clientWidth #offsetWidth

  以上DEMO 是常規情況下的區別,下面加上一個滾動條我們們再來觀察以下:#scrollWidth
## 

##   

clientWidth

offsetWidth
###################注意這裡不包含捲軸的長度##### ####### ######### #########這裡其實相當於內容的寬度################ ## ################################

 二、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 < 0 || position.top + target.offsetHeight < 0){42             return false;43         }44         if(position.bottom < 0 || position.right < 0){45             return false;46         }47         return true;48     }49 })();
登入後複製

  判断理由很简单,如果有一边的定位是负值,那么元素就不在视窗内。

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中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

建議:優秀JS開源人臉偵測辨識項目 建議:優秀JS開源人臉偵測辨識項目 Apr 03, 2024 am 11:55 AM

人臉偵測辨識技術已經是一個比較成熟且應用廣泛的技術。而目前最廣泛的網路應用語言非JS莫屬,在Web前端實現人臉偵測辨識相比後端的人臉辨識有優勢也有弱勢。優點包括減少網路互動、即時識別,大大縮短了使用者等待時間,提高了使用者體驗;弱勢是:受到模型大小限制,其中準確率也有限。如何在web端使用js實現人臉偵測呢?為了實現Web端人臉識別,需要熟悉相關的程式語言和技術,如JavaScript、HTML、CSS、WebRTC等。同時也需要掌握相關的電腦視覺和人工智慧技術。值得注意的是,由於Web端的計

PHP與JS開發技巧:掌握繪製股票蠟燭圖的方法 PHP與JS開發技巧:掌握繪製股票蠟燭圖的方法 Dec 18, 2023 pm 03:39 PM

隨著網路金融的快速發展,股票投資已經成為了越來越多人的選擇。而在股票交易中,蠟燭圖是常用的技術分析方法,它能夠顯示股票價格的變動趨勢,幫助投資人做出更精準的決策。本文將透過介紹PHP和JS的開發技巧,帶領讀者了解如何繪製股票蠟燭圖,並提供具體的程式碼範例。一、了解股票蠟燭圖在介紹如何繪製股票蠟燭圖之前,我們首先需要先了解什麼是蠟燭圖。蠟燭圖是由日本人

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

js和vue的關係 js和vue的關係 Mar 11, 2024 pm 05:21 PM

js和vue的關係:1、JS作為Web開發基石;2、Vue.js作為前端框架的崛起;3、JS與Vue的互補關係;4、JS與Vue的實踐應用。

如何在JavaScript中取得HTTP狀態碼的簡單方法 如何在JavaScript中取得HTTP狀態碼的簡單方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務

js刷新當前頁面的方法 js刷新當前頁面的方法 Jan 24, 2024 pm 03:58 PM

js刷新目前頁面的方法:1、location.reload();2、location.href;3、location.assign();4、window.location。詳細介紹:1、location.reload(),使用location.reload()方法可以重新載入目前頁面;2、location.href,可以透過設定location.href屬性來刷新目前頁面等等。

JS中__proto__與prototype的差別 JS中__proto__與prototype的差別 Feb 19, 2024 pm 01:38 PM

JS中__proto__和prototype是兩個與原型相關的屬性,它們在功能上稍有不同。本文將具體介紹並比較這兩者的區別,並提供相應的程式碼範例。首先,我們先來了解它們的意義和用途。 proto__proto__是物件的內建屬性,它用來指向該物件的原型。每個物件都有一個__proto__屬性,包括自訂物件、內建物件和函數物件。透過__proto__屬

JS 的 AI 時代來了! JS 的 AI 時代來了! Apr 08, 2024 am 09:10 AM

JS-Torch簡介JS-Torch是一種深度學習JavaScript函式庫,其語法與PyTorch非常相似。它包含一個功能齊全的張量物件(可與追蹤梯度),深度學習層和函數,以及一個自動微分引擎。 JS-Torch適用於在JavaScript中進行深度學習研究,並提供了許多方便的工具和函數來加速深度學習開發。圖片PyTorch是一個開源的深度學習框架,由Meta的研究團隊開發和維護。它提供了豐富的工具和函式庫,用於建立和訓練神經網路模型。 PyTorch的設計理念是簡單和靈活,易於使用,它的動態計算圖特性使

See all articles