- DOM简介
JS用document操作网页
这就是Document Object Model文档对象模型 - 获取元素的API
获取元素也叫标签
很多API
window.idxxx或者直接idxxx idxxx意思就是一个标签的id名字
document.getElementById(‘id’)用来查找id
document.getElementsByTagName(‘div’)[0] 用来查找所有div 这是一个伪数组
document.getElementsByClassName(‘red’)[0] 用来查找所有属性名为red的伪数组
document.querySelector(‘#id’)用来查找id
document.querySelectorAll(‘.red’)【0】用来查找所有的red
- 用哪一个
工作中用querySelecter和querySelecterAll
做demo直接用window.id
要兼容IE的可怜虫才用getElement(s)Byxxx - 获取特定的元素
获取html元素 document.documentElement
获取head元素 document.head
获取body元素 document.body
获取窗口 (窗口不是元素)
获取所有元素 document.all
这个document.all 在除IE外浏览器功能正常使用 但是值却认为是假 是第六个falsy值
- 元素的六层原型链
我们获取到的元素是一个对象 这个对象有六层原型
- 节点元素区别
节点Node包括以下几种
MDN有完整描述
x.nodeType得到一个数字
1表示元素Element 也叫标签Tag
3表示文本Text
8表示注释Comment
9表示文档Document
11表示文档片段DocumentFragment
记住1和3即可
- 创建元素的API
增:
创建一个标签节点
let div1=document.createElement(‘div’)
document.createElement(‘style’)
document.createElement(‘script’)
document.createElement(‘li’)
创建一个文本节点
document.createTextNode(‘你好’)
标签里面插入文本
div1.appendChild(text1)
div1.innerText=‘你好’或者div1.textContent=‘你好’
但是不能用div1.appendChild(‘你好’)
插入页面中
你创建的标签默认处于JS线程中
你必须把他插到head或者body里面 他才会生效
document.body.appendChild(div)
或者
已在页面中的元素.appendChild(div)
- appendChild
代码
页面中有div#text1 和div1#text2
let div=document.createElement(‘div’)
text1.appendChild(div)
text2.appendChild(div)
请问最终div出现在哪里?
答案:div出现在text2里面 因为一个元素不能出现在两个地方 除非复制一份
cloneNode(true/false)克隆 深克隆或者浅克隆
删
两种方法:
旧方法:parentNode.childChild(childNode)
新方法:childChild.remove()
思考:
如果一个node被移出页面(DOM树)
那么他还能再次回到页面中吗?
答案是可以的 因为只是移出页面 但是还在内存里 所以还可以重新加回来
如果不想再次回来的话 删除之后 再赋值为null
改
-
改属性:
写标准属性:
改class:div.className=‘red blue’(会覆盖原先的class)
改class:div.classList.add(‘red’)
改style:div.style=‘’但是这样改会直接覆盖原先所设置的所有
所以如果只改一部分 div.style.color=‘red’
大小写 background-color 在JS里应该写 backgroundColor
读标准属性
div.classList/a.href
div.getAttribute(‘class’)/a.getAttribute(‘href’)
两种方法都可以 但值可能稍微不同 麻烦的那种更保险 -
改事件处理函数
div.onlick默认为null
默认点击div不会有任何事情发生
但是如果你把div的onlick改写为一个函数fn
那么点击div的时候,浏览器就会调用这个函数
并且是这样调用的fn.call(div,event)
div会被当做this
event则包含了点击事件的所有信息,如坐标div.addEventLister
是div.onclick的升级版 -
改内容
改文本内容
div.innerText=‘XXX’
div.textContent=‘XXX’
两者几乎没有去区别 记住哪个用哪个 -
改html内容
div.innerHtml=‘重要内容’
改标签
div.innerHtml=‘’先清空
div.appendChild(div2)再加内容 -
改爸爸
想要找一个新爸爸
newParent.appendChild(div)
这样就从原来的地方消失了,之间变到新的地方去
查
-
查看元素的API
查爸爸:
node.parentNode或者node.parentElement
查爷爷
node.parentNode.parentNode
查子代
node.childNodes或者node.children
区别 第一个会把所有的空格也当成儿子 第二个则会只算元素
这两个查询会实时更新,如果用queryS查询到的 后续再对数据进行变化 但查询结果不变
查兄弟姐妹
node.parentNode.childNodes还要排除自己 这个还要排除空格
node.parentNode.children 还要排除自己查看下一个元素nextElementSibling
查看老大
node.firstChild
查看最后一个
node.lastChild
查看上一个哥姐
node.previousSibling
查看下一个弟妹
node.nestSibling 最后两个不会获取文本节点 -
遍历一个div里面的所有元素
**
travel1=(node,fn)=>{
fn(node)
if(node.children){
for(let i=0;i<node.children.length;i++){
travel1(node.children[i],fn)
}
}
}
travel1(div,(node)=>{console.log(node)})
DOM操作跨线程
- 跨线程操作
各线程各司其职
JS引擎不能操作页面,只能操作JS
渲染引擎不能操作JS,只能操作页面
document.body.appendChild(div1)
这句JS是如何改变页面的 - 跨线程通信
当浏览器发现JS在body里面加了一个div对象
浏览器就会通知渲染引擎在页面里也新增一个div元素
新增的div元素所有属性都照抄div1对象 - 插入新标签的完整过程
在div1放入页面之前
你对div1所有的操作都属于JS线程内的操作
把div1放入页面之时
浏览器会发现JS的意图
就会通知渲染线程在页面中渲染div1对应的元素
把div放入页面之后
你对div1的操作都有可能会触发重新渲染
对id的改动可能会重新渲染 也可能不会
对title的操作 也可能会重新渲染 也可能不会
如果你连续对div1多次操作,浏览器可能会合并成一次操作 也可能不会
比如:对一个元素 写两个CSS样式 然后第二个样式改变宽度 然后用js为元素添加css样式 随后 两个样式会被合并成一次操作 并不会有动画效果
但如果 在js添加两个样式之间 加上别的样式 比如 div.clientWith 获取宽度 在添加第二个样式 那样浏览器就会重新渲染 然后就会有动画效果 从原来的宽度过渡到200px - 属性同步
标准属性
对div1的标准属性的修改,会被浏览器同步到页面中
比如id className title
data-*属性
同上
非标准属性修改
对非标准属性的修改,则只会停留在JS线程中
不会同步到页面里
比如x属性
启示
如果你有自定义属性,又想被同步到页面中去,请使用data-作为前缀 然后用dataset.后缀 - property属性
JS线程中div1的所有属性,叫做div1的property
attribute也是属性
渲染引擎中div1对应标签的属性,叫做attribute
区别:
大部分时候,同名的property和attribute值相等
但如果不是标准属性,那么他俩只会在一开始时相等
但注意attribute只支持字符串
而property支持字符串布尔类型