第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的本质

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第1张图片

DOM的本质就是从HTML解析出来的一棵树,是树形的数据结构。如下




	
	Document


this is p

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第2张图片

 

3.DOM节点操作

获取DOM节点

 

dom.html



    
        
        
        
        dom 演示

        
    
    
        

一段文字 1

一段文字 2

一段文字 3

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])

运行结果

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第3张图片

dom-1.js

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

控制台结果

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第4张图片

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

运行结果 

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第5张图片

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') )

运行结果

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第6张图片

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第7张图片

所以最后的比较结论就是

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)

运行结果

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第8张图片

移动节点

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 )

运行结果

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第9张图片

直接获取节点再添加就是移动

 

获取子元素列表

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)

运行结果

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第10张图片

过滤filter之后只剩下p元素,filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。 

删除元素

删除上面过滤后的一个数组元素

div1.removeChild( div1ChildNodesP[0] )

结果

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第11张图片

 

5.DOM性能

DOM操作非常“昂贵”,我们需要避免频繁的DOM操作

对DOM查询做缓存操作

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第12张图片

将频繁操作改为一次性操作

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第13张图片

在console中敲一下

第9章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】_第14张图片

在执行最后list.apendChild(frag)之前,frag片段还在内存中,没有渲染,执行了之后就渲染在页面上

综上所述,DOM性能就是要记得做缓存和合并的处理,合并就是不要添加一次渲染一次。一次性添加到fragment再添加在DOM节点,这样只会渲染一次。

 

关注、留言,我们一起学习。

 

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

你可能感兴趣的:(javascript,前端,javascript)