热身
获取元素,也叫标签
window,idxxx或者之际idxxx document.getElementById('idxxx') document.getElementsByTagName('div')[0] document.getElementsByClassName('red')[0] document.querySelector('#idxxx') document.querySelectorAll('.red')[0]
用哪个??
工作中用querySelector 和 querySelectorAll
做demo直接用idxxx,千完别让人发现
要兼容IE的可怜虫才用getElement(s)ByXXX
获取特定元素
获取html元素
document.documentElement
获取head元素
document.head
获取body元素
document.body
获取窗口 -(窗口不是元素)
window
获取所有元素
document.all 这个doument.all是个奇葩,第6个Falsy值
获取到的元素是个啥
先然是一个对象,我们需要高清它的原型
抓一只div对象过来看看
- console.dir(div1)看原型链
- 告诉你一个秘密,Chorme显示错了
- 自身属性:className、id、style等等
- 第一层原型HTMLDivElement.prototype
- 这里面是所有div共有的属性,不用细看
- 第二层原型HTMLElementprototype
- 这里面是所有HTML标签共有的属性,不用细看
- 第三层原型Element.prototype
- 这里面是所有XML、HTML标签的共有属性,你不会以为浏览器只能展示HTML吧
- 第四层原型Node.protoype
- 这里面是所有节点共有的属性,节点包括XML标签文本注释、HTML标签文本注释等等
- 第五层原型EventTarget.protoype
- 里面最重要的函数属性是addEventListener
- 最后一层原型就是Object.prototype
节点?元素?傻傻分不清楚
节点Node包括以下几种
x.nodeType得到一个数组
1表示元素Element,也叫标签Tag
3表示文本Text
8表示注释Comment
9表示文档Document
11表示文档片段DocumentFragment
记住1和2就行了
增
创建一个标签节点
let div1 =document.createElement('div') document.createElement('style') document.createElement('script') document.createElement('li')
创建一个文本节点
text1 = document.createTextNode('你好')
标签里面插入文本
div1.appendChild(text1) div1.innerText = '你好' 或者 div1.textContent='你好' 但是不能用!! div1.appendChild('你好')
插入页面中
你创建的标签默认处于JS线程中
你必须把它查到head或者body里面,它才会生效
document.body.appenChild(div) //或者 已在页面中的元素.appendChild(div)
appendChild
页面中有div#test1和div#test2 let div =document.createElement('div') test1.appendChild(div) tast2.appendCHild(div) 它会只出现在!!! test2里面!!! 一个元素不能出现再两个地方 除非复制一份 怎么复制? let div2 = div1.cloneNode(true) 后面的true代表深拷贝,节点子孙后代全都拷贝
删
两种方法
旧方法:
parentNode.removeChild(childNode)
新方法:
childNode.remove()
思考:
如果一个node被移出页面,(DOM树)
那么它还可以再次回到页面中吗
可以的,他只是从树里面删掉了,还再内存里
document.body.appendChild(div2)
改
写标准属性
改class:div.className = 'red blue' (全覆盖) 改class:div.classList.add('red') 改style:div.style = 'width:100px;color:blue;' 改style的一部分:div.style.width = '200px' 大小写:div.style.backgroundColor = 'white' 改data-* 属性: div.dataset.x = 'frank'
读标准属性
div.classList / a.href div.getAttribute('class') <-好用点 / a.getAttribute('href') 两种方法都可以,但值可能稍微有些不同
该事件处理函数
div.onclick默认为null
默认点击div不会有任何事情发生
但是如果你把div.onclick改为一个函数fn
那么点击div的时候,浏览器就会调用这个函数
并且是这样调用的
fn.call(div,event)
div会被当作this
event则包含了点击事件的所有信息,如坐标
div.addEventListener
是div.onclick的升级版,之后再说
改内容
改文本
div.innerText = 'xxx' div.textContent = 'xxx' 两者几乎没有区别
改HTML内容
div.innerHTML = '<strong>重要内容</strong>'
改标签
div.innerHTML = '' //先清空 ddiv.appendChild(div2) //再加内容
改爸爸
想要找一个新爸爸?
newParent.appendChild(div) 直接这样就可以了,直接从原来的地方消失
查
查爸爸
node.parentNode 或者node.parentElement
查爷爷
node.parentNode.parentNode
查子代
node.childNodes或者node.children 思考:当子代变化时,两者也会实时变化吗? 会实时变化length 用querySelectorAll查找到获取 之后再把其中一个删除了,上面获取的也不会发生改变
查兄弟姐妹
node.parentNode.childNodes 不能算自己 node.parentNOde.children 推荐 不能算自己
查看老大
node.firstChild
查看老幺
node.lastChild
查看上一个哥哥/姐姐
node.previousSibling
查看下一个弟弟/妹妹
node.nextSibling
遍历一个div里面的所有元素
travel = (node,fn) => { fn(node) if(node.children){ for(let i = 0; i< node.children.length;i++){ travel(node.children[i],fn) } } } travel(div,(node) => console.log(node))
DOM操作是跨线程的
浏览器分为渲染引擎和JS引擎
各线程各司其职
Js引擎不能操作页面,只能操作JS
渲染引擎不能操作JS,只能操作页面
document.body.appenChild(div1)
这句JS是如何改变页面的?
跨线程通信
当浏览器发现JS在body里面加了个div1对象
浏览器就会通知渲染引擎在页面里也新增一个div元素
新增的div元素所有属性都照抄div1对象
插入新标签的完整过程
在div1放入页面之前
你对duiv1所有的操作都属于JS线程内操作
在div1放入页面之时
浏览器会发现JS的意图
就会通知渲染线程在页面中渲染div1对应的元素
把div1放入页面之后
你对div1的操作都有可能会触发重新渲染
div1.id='newxsad' 可能会重新渲染,也可能不会,例如修改的里面有css啥的,还是要重新渲染
div1.title = 'asda' 可能会重发渲染,也可能不会,例如div1::hover 里面改内容,里面还是要改内容,还是要重新渲染
如果你连续对div1多次操作,浏览器可能会合并成一次操作,也可能不会
属性同步
标准属性
对div1的标准属性的更改,会被浏览器同步到页面中
比如id className title等
data- * 属性
同上
非标准属性
对非标准属性的更改,只会停留在JS线程中
不会同步到页面里
气势
如果你有自定义属性,又想被同步到页面中,请使用data- 作为前缀
Property vs Attribute
property属性
Js线程中div1的所有属性,叫做div1的property
attribute也是属性
渲染引擎中div1对应标签的属性,叫做attribute
区别
大部分时候,同名的property和attribute值相等
但如果不是标准属性,那么它俩只会在一开始相等
但注意arribute只支持字符串
而property支持字符串、布尔等类型