网页其实是一棵树
JS如何操作这棵树
- 浏览器往window上加一个document即可
JS用document操作网页(DOM树)
- 这就是Document Object Model 文档对象模型
获取元素(Element),也叫标签(tag)
有很多API
-
window.idxxx或者直接idxxx (名字不跟全局属性冲突是可以用这个)
-
document.getElementById('Idxxx') (与全局属性冲突时用这个)
-
document.getElementsByTagName('div')[0] (找到一个标签名为div的元素,前面是一个伪数组,[]里面是代表div元素里面的第几个)
-
document.getElementsByClassName('red')[0] (根据类名来获取class=red的标签)
-
document.querySelector('#idxxx') (例如:document.querySelector('div>span:nth-child(2)'))
-
document.querySelectorAll('.red')[0] (获取符合条件的所有标签)
练练手
- 假设页面中有如下元素
<div id="test" class="red">demo</div>
以下获取该 div 元素的代码中,正确的有
-
document.getElementById('test')
-
document.getElementsByClassName('red')[0]
-
window.test
-
document.querySelector('#test')
-
document.querySelectorAll('#test')[0]
获取特定元素
获取html元素
- document.documentElement(document.documentElement.tagName打印出来的是大写的HTML)
获取head元素
- document.head
获取body元素
- document.body
获取窗口(窗口不是元素)
- window
获取所有元素
-
document.all(是IE发明的,用来分辨是不是IE,它过不了if,但是可以直接用)
-
这个document.all 是个奇葩,第六个falsy值
获取到的元素是个啥(显然是一个对象)
div完整原型链(自身属性和共有属性)
节点?、元素?
节点Node包括以下几种
-
MDN有详细的描述,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('你好')(注意:text是对象,'你好'是字符串)
插入页面中
-
你创建的标签默认处于JS线程中
-
你必须把它插到head或者body里面,它才会生效
-
document.bady.appendChild(div)
-
或者,已在页面中的元素 .appendChild(div)
appendChild
- 答案:text2里面,一个元素不能出现在两个地方,除非复制一份
删
两种方法
旧方法:parentNode.remoteChild(childNode)
新方法:childNode.remove()
- 移回页面:
document.head/body.appendChild(div)
改属性
读标准属性
改事件处理函数
- 注意:x是event, test是this
改内容
改文本内容
-
div.innerText = 'xxx'
-
div.innerContent = 'xxx'
-
两者几乎没有区别
改HTML内容
- div.innerHTML = '重要内容'
改标签
-
div.innerHTMl = ''//先清空
-
div.appendChild(div2) //在加内容
改父级(改爸爸)
-
newParent.appendChild(div)
-
直接这样就可以了,直接从原来的地方消失
查
查父级(查爸爸)
- node.parentNode或者node.parentElement
查父级的父级(查爷爷)
- node.parentNode.parentNode
查子级(查子代)
-
node.childNodes或者node.children
-
注意:childNodes是Node提供的,children 是Element提供的,第一种会把回车空格算下来,包括文本节点,第二个不包括文本节点。当用document.querySelectorAll('')获取元素时则子代变化时,不会随时改变属性。
查兄弟姐妹
-
node.parentNode.childNode还要排除自己
-
node.parentNode.children还要排除自己
let sibling = []
let c = div2.parentElement.children
for(let i=0;i<c.length;i++){
if(c[i] !== div2){
sibling.push(c.[i])
}
}
查看老大
- node.firstChild
查看老幺
- node.lastChild
查看上一个哥哥/姐姐
- node.previousSibling
查看下一个弟弟/妹妹
- mode.nextSibling
遍历一个div里面的所有元素
DOM操作是跨线程的
- 浏览器功能划分渲染引擎和JS引擎
跨线程操作
各线程各司其职
-
JS引擎不能操作页面,只能操作JS
-
渲染引擎不能操作JS,只能操作页面
-
document.body.appendChild(div1)
跨线程通信
-
当浏览器发现JS在body里面加了个div1对象
-
浏览器就会通知渲染引擎在页面里也新增一个div元素
-
新增的div元素所有的属性都照抄div1对象
跨线程操作图
插入新标签的完整过程
在div放入页面之前
- 你对div所有的操作都属于JS线程内的操作
把div放入页面之时
- 浏览器会发现JS对应的意图,就会通知渲染进程在页面中渲染div1对应的元素
把div1放入页面之后
-
你对div1的操作都有可能会触发重新渲染
-
div1.id ='newId' 可能会重新渲染,也可能不会
-
div1.title ='new' 可能会重新渲染,也可能不会
-
如果你连续对div1多次操作,浏览器可能会合并成一个操作,也可能不会
属性同步
标准同步
-
对非标准属性的修改,则只会停留在JS线程里
-
比如id、className、title等
data-* 属性
- 同上
非标准属性
- 对应标准属性的修改,则只会停留在JS线程中,不会同步到页面
启示
- 如果有自定义属性,不想同步到页面中,请使用data-* 属性
property V.S Attribute
property属性
- JS线程中div1的所有属性,叫做div1的property
attribute也是属性
- 渲染引擎div1 对应的标签的属性,叫做attribute
区别
-
大部分时候,同名的property和attribute值相等
-
但如果不是标准的属性,那么他两只会一开始相等
-
property支持字符串、布尔等类型
-
attribute只支持字符串