返回章节目录
目录
1.从JS基础到JS-Web-API
2.DOM的本质
3.DOM节点操作
获取DOM节点
用JS操作DOM节点的property、attribute
4.DOM结构操作
新增节点
移动节点
获取子元素列表
删除元素
5.DOM性能
对DOM查询做缓存操作
将频繁操作改为一次性操作
JS基础知识,规定语法(ECMA262标准)
JS Web API,网页操作的API(W3C标准)
前者是后者的基础,两者结合才能真正实际应用
JS基础知识有哪些?
变量的类型和计算、原型和原型链、作用域和闭包(还有异步,异步是借用JS Web API去实现的)
JS Web API有哪些?
DOM、BOM、事件绑定、ajax、存储
DOM的本质就是从HTML解析出来的一棵树,是树形的数据结构。如下
Document
this is p
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])
运行结果
dom-1.js
const pList = document.querySelectorAll('p')
console.log('pList', pList)
控制台结果
0号元素的p#p1是p元素有id="p1"
这些都比较基本,菜鸟教程和官方文档一大堆
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'
})
将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] )
结果
DOM操作非常“昂贵”,我们需要避免频繁的DOM操作
在console中敲一下
在执行最后list.apendChild(frag)之前,frag片段还在内存中,没有渲染,执行了之后就渲染在页面上
综上所述,DOM性能就是要记得做缓存和合并的处理,合并就是不要添加一次渲染一次。一次性添加到fragment再添加在DOM节点,这样只会渲染一次。
关注、留言,我们一起学习。
===============Talk is cheap, show me the code================