原生js操作DOM基础

时间:2022-09-16 23:01:58

原文参考http://mp.weixin.qq.com/s?__biz=MzU3MDA0NTMzMA==&mid=2247485490&idx=1&sn=15197b4b53e0669e4a017e54a31fb39c&source=41#wechat_redirect

使用原生js为了提高效率,纯js操作dom
一 查询DOM
document.querySelector()参数是任意css选择器格式,只会返回第一个匹配到值
document.querySelectorAll()同上,返回结果不同,会返回所有查找到的值

尽量在父元素中查找指定dom,减少document的整个文档查找,这样可以简化选择器并提高性能。

与getElementsByTagName()这些方法的比较,querySelector()的结果不是动态的,当我们动态添加元素时,集合不会更新
代码:
const elements1 = document.querySelectorAll('div')
const elements2 = document.getElementsByTagName('div')
const newElement = document.createElement('div')
document.body.appendChild(newElement)
elements1.length === elements2.length // 0 1 结果false

querySelectorAll()返回的结果不用调用node方法,结果也不是一个数组(是伪数组),需要转为数组才能使用数组的方法
const myElements=document.querySelectorAll('.cla')
Array.from(myElements).forEach(doSomeThing)
Array.prototype.forEach.call(myElements,doSomeThing)
[].forEach.call(myElements,doSomeThing)

每个元素都有一些引用‘家族’的不需要说明的只读属性(即element属性),并且是动态的,基于元素的
myElements.children子节点
myElements.firstElementChild第一个子节点
myElements.lastElementChild最后一个子节点
myElements.previousElementSibling前一个子节点
myElements.nextElementSibling后一个子节点
node属性,除了parentElement可以是任何类型节点
myElements.childNodes
myElements.firstChild
myElements.lastChild
myElements.previousSibling
myElements.nextSibling
myElements.parentNode
myElements.parentElement

通过nodeType来判断节点的类型

检查节点的原型链可以使用instanceof

二 修改类和属性
修改类
myElement.classList.add()
myElement.classList.remove()
myElement.classList.toggle()
访问属性
myElement.value
myElement.value = 'test'// 赋值
设置多属性
Object.assign(myElement,{
value:'test',
id:'app'
})
以下方法会导致浏览器重绘消耗性能
getAttribute()
setAttribute()
removeAttribute()

三添加css样式
使用驼峰形式
myElement.style.marginLeft = '1px'// 只会获取明确属性
window.getComputedStyle(myElement)// 可以获取次元素所有css属性集合,包括继承下来的
window.getComputedStyle(myElement).getPropertyValue('width')// 获取全部集合中的一种(如宽度)


四修改DOM
element1.appendChild(element2)
element1.insertBefore(element2,element3)// 在容器element1中,将element2插入到element3之前

五克隆一个元素
let myEleClone = myElement.cloneNode()// 参数为true将创建一个深层副本,它的子元素也会被克隆

六创建
创建元素
document.createElement('div')
创建文本节点
document.createTextNode('hell')

七删除
parentBox.removeChild(myElement)// 从父容器中删除子元素
myElement.parentNode.removeChild(myElement)

八读写元素属性
innerHTML='<p>test</p>'// 元素中添加html内容
textContent='test'// 只能添加纯文本

九事件监听
使用addEventListener方法可以不断绑定事件,事件都会触发
myElement.addEventListener('click',function(event){
console.log(event.target);
})
event.target是触发事件的元素

阻止默认事件e.preventDefault()
阻止事件冒泡e.stopPropagation()

myElement.addEventListener('click',function(){},true)
第一个参数是事件类型,第二个参数是回调函数,第三个参数是布尔值,true表示事件在捕获阶段执行false事件在冒泡阶段执行。默认是false

removeEventListener()删除事件监听器
myElement.addEventListener('click',function(e){})// 第一个参数是事件类型,第二个参数是回调函数

事件委托
列表的每个列表需要添加绑定事件,可以使用这种方式,在父元素上绑定事件,利用冒泡原理在判断触发事件的元素,节约性能
parentBox.addEventListener('click',function(e){
console.log(e.target);
})

十 动画
使用window.requestAnimationFrame()来同步更新,将更改安排到浏览器下次重绘中。
格式
const start = window.performance.now()
const duration = 2000
window.requestAnimationFrame(function fadeIn(now){
consot progress = now - start
myElement.style.opacity = progress / duration
if(progress < duration){
window.requestAnimationFrame(fadeIn)// 递归
}
})

十一 封装自己方法
const $ = function $(selector, context = document) {
const elements = Array.from(context.querySelectorAll(selector))
return {
elements,
html(newHtml){
this.elements.forEach(element => {
element.innerHTML = newHtml
})
},
css (newCss) {
this.elements.forEach(element => {
Object.assign(element.style, newCss)
})
return this
},
on (event, handler, options){
this.elements.forEach(element => {
element.addEventListener(event, handler, options)
})
return this
}
}
}