第9章 JS-Web-API-DOM【學會DOM,才能具備網頁開發的基礎】

返回章節目錄

目錄

1.從JS基礎到JS-Web-API

2.DOM的本質

3.DOM節點操作

獲取DOM節點

用JS操作DOM節點的property、attribute

4.DOM結構操作

新增節點

移動節點

獲取子元素列表

刪除元素

5.DOM性能

對DOM查詢做緩存操作

將頻繁操作改爲一次性操作


 

1.從JS基礎到JS-Web-API

JS基礎知識,規定語法(ECMA262標準)

JS Web API,網頁操作的API(W3C標準)

前者是後者的基礎,兩者結合才能真正實際應用

JS基礎知識有哪些?

變量的類型和計算、原型和原型鏈、作用域和閉包(還有異步,異步是借用JS Web API去實現的)

JS Web API有哪些?

DOM、BOM、事件綁定、ajax、存儲

 

2.DOM的本質

DOM的本質就是從HTML解析出來的一棵樹,是樹形的數據結構。如下

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<div><p>this is p</p></div>
</body>
</html>

 

3.DOM節點操作

獲取DOM節點

 

dom.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>dom 演示</title>

        <style>
            .container {
                border: 1px solid #ccc;
            }
            .red {
                color: red;
            }
        </style>
    </head>
    <body>
        <div id="div1" class="container">
            <p id="p1">一段文字 1</p>
            <p>一段文字 2</p>
            <p>一段文字 3</p>
        </div>
        <div id="div2">
            <img src="https://img3.mukewang.com/5a9fc8070001a82402060220-100-100.jpg"/>
        </div>
        <ul id="list">
        </ul>

        <script src="./dom-1.js"></script>
    </body>
</html>

dom-1.js

const div1 = document.getElementById('div1')
console.log('div1\n', div1)

const divList = document.getElementsByTagName('div') // 集合
console.log('divList.length', divList.length)
console.log('divList[1]', divList[1])

運行結果

dom-1.js

const pList = document.querySelectorAll('p')
console.log('pList', pList)

控制檯結果

0號元素的p#p1是p元素有id="p1"

這些都比較基本,菜鳥教程和官方文檔一大堆

 

用JS操作DOM節點的property、attribute

dom-1.js

const pList = document.querySelectorAll('p')
const p1 = pList[0]

// property 形式
p1.style.width = '100px'
console.log( p1.style.width )
p1.className = 'red'
console.log( p1.className )
console.log(p1.nodeName)
console.log(p1.nodeType) // 1

運行結果 

dom-1.js

// attribute形式
p1.setAttribute('data-name', 'imooc')
// p1.data-name="imooc"; // 這是錯誤的,不能和操作property形式替換使用
console.log( p1.getAttribute('data-name') )
// property形式
p1.style.fontSize="50px"; // 這是正確的,可以和操作property形式替換使用
// p1.setAttribute('style', 'font-size: 50px;')
console.log( p1.getAttribute('style') )

運行結果

所以最後的比較結論就是

property和attribute形式都可以修改節點的屬性,但是對於新增或刪除的自定義屬性,能在html的dom樹結構上體現出來的,就必須要用到attribute形式了。

這兩種方式我個人都不喜歡。

// attribute
p1.setAttribute('data-name', 'imooc')
// p1.data-name="imooc"; // 這是錯誤的,不能和操作property形式替換使用
console.log( p1.getAttribute('data-name') )
// p1.removeAttribute('mytest') // 必須attribute形式刪除

// property
p1.removeAttribute('font-size') // property和attribute形式刪除都可以,這裏刪除後getAttribute爲null,沒有font-size屬性了
// p1.style.fontSize="";  // 和上面一句效果一樣
// p1.style.fontSize="50px"; // 這是正確的,可以和操作property形式替換使用,新增font-size並設置50px
// p1.setAttribute('style', 'font-size: 50px;')
console.log( p1.getAttribute('style') )

 

如果使用property這種方式要給HTMLElement添加多個行內樣式時,需要顯式的書寫多次

這種方式是一種低效而又冗餘,甚至是難於維護的方式。事實上如果需要通過使用JavaScript的API給HTMLElement同時添加多個樣式,除了給元素添加一個類名(後面會介紹)之外,還可以使用.style.cssText = ''這種方式或者使用.setAttribute('style', '')方式:

// 使用 
bodyEle.style.cssText = 'background-color: red; color: green; font-size: 1rem' 
// 或使用 
bodyEle.setAttribute('style', 'font-size: 1rem;color: green; background-color: yellow')

請注意:不管使用上面哪種方式,都將完全重置HTMLElement元素的內聯樣式,因此需要在參數中包含所有需要的樣式(甚至是以前未更改的樣式)。

上面是老師的講解,我個人習慣cssText的方式,爲什麼呢?爲了減少迴流次數,你要是設置一次背景色,重繪一次,再設置font-Size又要回流一次...屬性多了就很影響性能。

隨着瀏覽器的發展,我們可以使用JavaScript的一些新的API來達到同樣的效果,比如Object.assign()給HTMLelement.style一次性添加多個行內樣式

Object.assign(bodyEle.style, {
    backgroundColor: '#f36', 
    margin: '20px', 
    border: '1rem solid green' 
})

 

 

4.DOM結構操作

將dom.html引入的dom-1.js改爲dom-2.js

新增節點

dom-2.js

const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')

// 新建節點
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入節點
div1.appendChild(newP)

運行結果

移動節點

dom-2.js

const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')

// 新建節點
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入節點
div1.appendChild(newP)

// 移動節點
const p1 = document.getElementById('p1')
div2.appendChild(p1)

// 獲取父元素
console.log( p1.parentNode )

運行結果

直接獲取節點再添加就是移動

 

獲取子元素列表

dom-2.js

const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')

// 新建節點
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入節點
div1.appendChild(newP)

// 移動節點
const p1 = document.getElementById('p1')
div2.appendChild(p1)

// 獲取父元素
console.log( p1.parentNode )

// 獲取子元素列表
const div1ChildNodes = div1.childNodes
console.log( div1.childNodes )
const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child => {
    if (child.nodeType === 1) {
        return true
    }
    return false
})
console.log('div1ChildNodesP', div1ChildNodesP)

運行結果

過濾filter之後只剩下p元素,filter() 方法創建一個新數組, 其包含通過所提供函數實現的測試的所有元素。 

刪除元素

刪除上面過濾後的一個數組元素

div1.removeChild( div1ChildNodesP[0] )

結果

 

5.DOM性能

DOM操作非常“昂貴”,我們需要避免頻繁的DOM操作

對DOM查詢做緩存操作

將頻繁操作改爲一次性操作

在console中敲一下

在執行最後list.apendChild(frag)之前,frag片段還在內存中,沒有渲染,執行了之後就渲染在頁面上

綜上所述,DOM性能就是要記得做緩存和合並的處理,合併就是不要添加一次渲染一次。一次性添加到fragment再添加在DOM節點,這樣只會渲染一次。

 

關注、留言,我們一起學習。

 

===============Talk is cheap, show me the code================

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章