JavaScrip 之 DOM

来源:https://www.cnblogs.com/gaoguowen/archive/2019/12/17/12056235.html
-Advertisement-
Play Games

DOM 樹 HTML 文檔的骨幹是標簽。 根據文檔對象模型(DOM),每個HTML標簽都是一個對象,同樣標簽內的文本也是一個對象。因此這些對象都可通過 JavaScript 操作 如果文檔中有空格(就像任何字元一樣),那麼它們將成為 DOM 中的文本節點,如果我們刪除它們,則不會有任何內容。 `` ...


DOM 樹

HTML 文檔的骨幹是標簽。
根據文檔對象模型(DOM),每個HTML標簽都是一個對象,同樣標簽內的文本也是一個對象。因此這些對象都可通過 JavaScript 操作
如果文檔中有空格(就像任何字元一樣),那麼它們將成為 DOM 中的文本節點,如果我們刪除它們,則不會有任何內容。
<head> 之前的空格和換行符被忽略
</body> 之後放置了一些東西,那麼它會自動移動到 body 內部,因為 HTML 規範要求所有內容必須位於 內。所以 後面可能沒有空格。

通常再瀏覽器中的文本不會顯示開頭/結尾的空文本節點,標簽之間也不會顯示空文本節點。

如果瀏覽器遇到格式不正確的HTML,在形成DOM是會自動修複它
如:
<html> 即使不在文檔中,瀏覽器也會自動創建它

按DOM規範,table 必須具有 <tbody>,因此table中未使用<tbody> 形成DOM時會自動添加。

其它 節點:
註釋不會以任何方式影響視覺表示,但是必須遵循一條規則 —— 如果HTML中有東西,那麼它必須在DOM樹中。
HTML中所有內容都是DOM的一部分,
註釋是一個節點甚至<!DOCTYPE...>也是一個節
DOM總有12種節點

遍歷DOM節點

所有對DOM的操作都是從document對象開始,將這個對象賦予一個變數,對其進行修改操作

最頂端的節點

DOM節點樹可以通過 document屬性使用
頂端的節點對應<html> 並且 <html> = document.documentElement
<body> = document.body,<head> = document.head
docment.body可能為null,如果將script腳本放入 <head>標簽種,那麼此腳本無法訪問到document.body,即為null

childNodes

childNodes 集合提供對所有子節點包括文本節點的訪問,它看起來是一個數字,實際上只是一個可迭代的類數組對象,因此沒有數組的方法
所有的Dom 集合節點都是只讀的無法通過賦值來替換對應的節點
除小部分節點,幾乎所有的DOM集合都是實時的,它們反應的是DOM的實時狀態
不要是有 for...in來遍歷DOM集合,此方法會列出其所有的屬性。
註意此屬性只能訪問到當前script腳本之前對應的節點
可以通過elem.hasChildNodes()來檢測是否含有子節點

parentNOde / siblingNode

通過elem.parentNode可訪問當前節點的父節點
通過elem.previousSibling/elem.nextSibling可訪問對應節點的上/下兄弟節點

只訪問元素節點

  • children: 只獲取類型為元素節點的子節點
  • firstElementChild,lastElementChild:只獲取第一或最後一個子元素
  • previousElementSibling, nextElementSibling:兄弟元素
  • parentElement:父元素

parentElement 可能為null,因為其方法返回的是父元素節點,而parentNode返回的是任何類型的父節點,因此,document.documentElement.parentElement === null

HTMLCollection (動態)

通過元素查找子元素如果子元素是一個集合將返回 HTMLCollection 類數組

let tb = documet.querySelector('table')
let tbs = tb.tBodies  // HTMLCollection [tbody]
let trs =tbs.rows // HTMLCollection [tr,tr,tr,...]
let tr1 = trs[0]
    tr1.sectionRowIndex //0 當前 tr 在集合中的位置
    tr1.rowIndex // 1 當前 tr 在整張表中的 位置
let tds = tr1.cells // HTMLCollection [td,td,td,...]
    td[0].cellIndex //0 當前 td 在父元素 tr節點 中的位置

NodeList (靜態 如果使用迴圈創建查詢的元素,新的元素不會實時加入到NodeList中)

通過 document 中的方法 document.querySelectorAllelem.querySelectorAll獲取的元素集合將返回NodeList類數組
getElement* 方法只能通過 document對象調用

let divs = document.querySelectorAll('div') // NodeList(4) [div.Owen, div#modal, div.main, div]
 document.getElementsByTagName('div')//HTMLCollection [div.Owen]

matches

elem.matches(css)會檢測 elem是否匹配到給定的css選擇器,返回 true 或 false

closest

elem.closest(css)此方法會查找css選擇器匹配到的祖先HTML,包括自身,並返回最先找到的元素

contains

elem.catains(dom) 判斷 dom 是否為 elem 的後代,或等於elem,返回true 或false

節點屬性

所有的節點都繼承自根節點 EventTarget

  • EventTarget:作為基礎,讓所有DOM 節點都支持事件
  • Node:作為DOM 節點的基礎,提供DOM樹的核心功能:parentNodenextSiblingpreviousSiblingChildNodes等(只能讀取 getter);文本節點 Text,元素節點Element,註釋節點Comment都繼承自Node
  • Element:做為DOM 元素的基類。提供元素級導航: nextElementSiblingchildrengetElement*querySelector等等,瀏覽器不僅支持HTML,還支持 XML、SVG等,分別對應的基類 HTMLElementXMLElementSVGElement
  • HTMLElement:作為所有元素的基類,被各種元素繼承
innerHTML 和 outerHTML
  • innerHTML: 獲取或替換當前節點的所有子節點(不包含當前節點)
  • outerHTML: 替換當前節點

文檔片段 DocumentFragment

用於存儲節點的包裝器,不會再瀏覽器中展示,需要通過插值方法才能展示包裝器裡面的內容

function creatEl(){
let frag = new DocumentFragment();
 for (let i=1;i<4;i++) {
let li = document.createElement('li')
  li.append(i)
  frag.append(li)
}

return frag
}
ul.append(creatEl())

類樣式的修改等操作

elem.className 對應元素的類名,多個類目以空格分隔

ul.className // "class1 class2 ..."

同時還要一個 elem.classList 對象可訪問類名,它以類數組的方式存在,同時具有 add/remove/toggle/contains 等方法

ul.classList //  DOMTokenList(2) ["333", "444", value: "333 444"]
ul.classList.add('class1')
ul.classList.remove('class1')
ul.classList.toggle('class1') // true 新增
ul.classList.toggle('class1') // false 去除
ul.classList.contains('class1') //false 是否包含

通常我們使用 style.*單獨對樣式屬性進行修改,如果想要對多種樣式進行調整可使用 cssText此方法會直接替換之前的樣式

ul.style.cssText = `
    color: red ;
    background-color: skyblue;
    width: 20px;
    text-align: center;`

style 屬性僅針對 style 屬性值進行操作,無法讀取css類中的屬性值

<style>
body {margin:20 auto;}
</style>
<script>
document.body.style.margin // ""
</script>

這時我們需要使用 getComputedStyle(el,[,pseudo])方法來獲取對應的值
如果不傳參或值無意義,將返回元素所有樣式,其屬性值都為解析值,如 font-size:1em 最後獲取的可能為解析後的值"16px"

let res = getComputedStyle(document.body)
res.marginTop // "20px"
res.margin // 谷歌 "20px 0px" 在火狐中為 ""  因此訪問確切屬性值須使用完整屬性名

獲取元素的尺寸和滾動距離

  • offsetTop/Left: 獲取相對於設置有position屬性為 absolute relative、fixed 的值或td、th、table、body的元素的距離
  • offsetWidth/Height:獲取外部寬度/高度,包含border,padding,scrollbar (display:none 或自身不在文檔中,其值為0或null,由此可判斷當前元素是否被隱藏)
  • clientTop/Left:獲取內側與外側的距離(滾動條在左邊時,包含滾動條的寬度)
  • clientWidth/Height:獲取可視區內容的寬高,即不包含滾動條和border
  • scrollWidth/Height:獲取全部內容(包含隱藏部分)的寬高
  • scrollTop/Left: 獲取 元素隱藏部分的上/左距離,包含border,這兩個屬性可修改,其它屬性能只讀取

HTML 文件里如果沒有 <!DOCTYPE HTML> 上述的屬性可能會有所不同,這不是一個 JavaScript 的問題,但會影響到 JavaScript。

滾動瀏覽器視窗

pageXOffset/pageYOffset: 獲取可視視窗移動的距離 無法設值

可通過 window.scrollBy, window.scrollTo, elem.scrollIntoView來滾動視窗

  • scrollBy(x,y):滾動頁面至相對於現在位置的(x,y)位置
  • scrollTo(x,y):滾動到頁面相對於文檔左上方的(x,y),位置,類似於 scrollTop/scrollLeft
  • elem.scrollIntoView(truly):如果 truly 為真則使 當前元素 滾動至視窗頂部,元素頂部與視窗頂部對齊,如果truly 為false,則當前元素底部與視窗底部對齊。

如果禁止視窗滾動可使 樣式屬性 overflow 值為 hidden

坐標

getBoundingClientRect()`方法獲取相對於可視視窗的坐標對象

其所有屬性都是以可視視窗左端(X)和頂部(Y)為起點

ul.getBoundingClientRect()
/*

DOMRect {
    bottom: 829.59375  // 元素底部的Y坐標
    height: 210  // 元素真實高度
    left: 0 // 元素左邊 X 坐標
    right: 1903 // 元素右邊 X 坐標
    top: 619.59375 // 元素頂部 Y 坐標
    width: 1903 // 元素自身真實寬度即不包含滾動條
    x: 0
    y: 619.59375
}

*/
document.elementFromPoint

document.elementFromPoint(x,y)返回可視視窗坐標(x,y),最頂層的元素

let elem = document.elementFromPoint(0,0) // <p>556666</p>

如果x,y不在正常範圍內將返回 null,

相對於文檔坐標,JS並未提供原生標準方法,可自己寫一個出來:
function getDomCoords(el){
    let {top,left} = el.getBoundingClientRect()
  return {
    top:top+ window.pageYOffset,
    left:left+window.pageXOffest
  }
}

Owen 的個人博客
博客園


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 拖拽 ~~~javascript ~~~ ...
  • Ajax簡介 一門非同步的載入技術,局部刷新 非同步載入,可以在不重載整個網頁的前提下,進行局部刷新 分為原生和JQ兩種 JSON數據格式 Json對象轉字元串: JSON.stringify() 字元串轉Json對象:JSON.parse() 前後端數據交互 html文件 py文件 Ajax局部刷新 ...
  • 事件的傳播 ~~~javascript ~~~ ...
  • 事件的綁定 ~~~javascript btn01 ~~~ ...
  • 在潤乾官方線上 demo的 "交互報表" 中,有介紹 "點擊表頭排序" 的報表案例,該報表針對普通統計類報表。對於使用大數據集的報表,當按照此方式改造時發現排序沒起作用或僅對第一頁或前幾頁排序,後面的都沒成功。 要想瞭解啥原因導致?就需要分析該報表的做法及知道大數據集的取數原理。 首先,來分析下線上 ...
  • 最近在學習react框架,之前一直都是用vue 開發,知道在vue 中知道如何配置一下相關的webpack 有助於開發,學react 過程中,我也在想這些該怎麼配置啊,所以就有這篇文章。 這篇文章主要是講 react-create-app 生成的項目利用 react-app-rewired 和 cu ...
  • 小程式APP生命周期需要先從app.js這個文件開始,App() 必須在 app.js 中調用,必須調用且只能調用一次,app.js中定義了一些應用的生命周期函數 onLaunch 當小程式初始化完成時,會觸發 onLaunch(全局只觸發一次) onShow 當小程式啟動,或從後臺進入前臺顯示,會 ...
  • 之前文章有寫到vue構造函數的實例化過程,只是對vue實例做了個粗略的描述,並沒有說明vue組件實例化的過程。本文主要對vue組件的實例化過程做一些簡要的描述。 組件的實例化與vue構造函數的實例化,大部分是類似的,vue的實例可以當做一個根組件,普通組件的實例化可以當做子組件。真實的DOM是一個樹 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...