### DOM数
> dom tree
> 当浏览器加载HTML页面的时候,首先就是DOM结构的计算,计算出来的DOM结构就是DOM树(把页面中的HTML标签像树状结构一样,分析出之间的层级关系)
window
document
html
head body
meta title link style.. div ul li script
DOM树描述了标签和标签之间的关系(节点间的关系),我们只要知道任何一个标签,都可以依据DOM中提供的属性和方法,获取到页面中任意一个标签或者节点
### 在js中获取DOM元素的方法
“ getElementById ”
>通过元素的ID获取指定的元素对象,使用的时候都是“document.getElementById('')” 此处的document是限定了获取元素的范围,我们把它称为“上下文(context)”
强调点:
1.getElementById的上下文只能是document
-因为严格意义上,一个页面中的ID是不能重复的,浏览器规定在这个文档中既可以获取这个唯一的ID
2.如果页面中的ID重复了。我们基于这个方法只能获取到第一个元素,后面相同ID元素无法获取到
3.在IE6-7浏览器中,会把表单元素(input...)的name属性值当作ID来使用(建议:使用使用表达元素的时候,不要让name和id值有冲突)
“ getElementsByTagName ”
’[context].getElementsByTagName‘在指定的上下文中,根据标签名获取到一组元素集合(HTMLCollection)
强调点:
1.获取的元素集合点是一个类数组(不能直接的使用数组中的方法)
var oBox = document.getElementById('box'),
HTMLCollection = oBox.getElementsByTagName('div')
2.他会把当前上下文中,子子孙孙(后代)层级内的标签都获取到(获取的不仅仅是儿子级的)
3.基于这个方法获取到的结果永远都是一个集合(不管里面的是否有内容,也不管有几项,它是一个容器或者集合),如果想操作集合中具体的某一项,需要基于索引获取才可以 ....
“ getElementsByClassName ”
'[context].getElementsByClassName()'在指定的上下文中,基于元素的样式类名(class="xxx")获取一组元素集合
强调点:
1.真实项目中,我们经常基于样式类来给元素设置元素,所以在js中,我们也会经常基于样式类来获取元素,但是此方法在IE6-8下不兼容
“ getElementsByName ”
"document.getElementsByName()"它的上下文也只能是document,在整个文档中,基于元素的name属性值获取一组节点集合(也是一个类数组)
前调点:
1.在IE浏览器中(IE及以下版本),只对表单的name属性起作用(正常来说,我们项目中只会给表单元素设置name,给非表单元素name,其实是一个不太符合的设计)
“ querySelector ”
'[context].querySelector()' 在指定的上下文中基于选择器(类似于css选择器)获取到指定的元素对象(获取的是一个元素,哪怕选择器匹配了多个,我们之获取一个)
“ querySelectorAll ”
在querySelectorAll的基础上,我们获取到选择器匹配到的所有元素,结果是一个基点集合(nodeList)
强调点:
querySelector/querySelectorAll都是不兼容IE6-8浏览器的(不考虑兼容的情况下,我梦能用byID或者其他方式获取的,也尽量不要用这两个方法,这两个方法性能消耗比较大)
document.querySelector("#HAHA")
document.querySelectorAll("#HAHA")
document.querySelectorAll('.box>div')
document.querySelectorAll('.box>div')
document.querySelectorAll('[name="hobby"]')
“ document.head ”
获取HEAD元素对象
“ document.body ”
获取BODY元素对象
“ document.documentElement ”
获取HTML元素对象
```javascript
//=>需求: 获取浏览器一屏幕的宽度和高度(兼容所有的浏览器)
document.documentElement.clientWidth ||
document.body.clientWidth
document.documentElement.clientHeight ||
document.body.clientHeight
```
### 面试题:获取当前页面中所有ID为HAHA的元素(兼容所有浏览器)
```javascript
//=>不能使用querySelectorAll
/* 思路
* 1.首先获取当前文档中所有的HTML标签
* 2.依次遍历这些元素标签对象,谁的ID等于HAHA,我们就把谁存储起来即可
*/
```
function queryAllById(id){
var nodeList = document.getElementsByTagName('*'); //=>基于通配符*获取到这个文档中所有的标签
// =>遍历集合中的每一项,把元素ID和传递ID相同的这一项存储起来
var ary = [];
for(var i = 0;i<nodeList.length;i++){
var item = nodeList[i]
item.id === id ? ary.push[item]:null
}
return ary;
}
queryAllById("HAHA");
console.log(HAHA); //在js中,浏览器中会自动把元素的id拿过来当变量用(不需要自己获取设置,而且ID重复,获取的结果就是一个集合,包含所有ID项,不重复就是一个元素对象(类似ById获取的结果))
节点与描述节点之间的属性
### 节点(node)
>在一个HTML文档中出现的所有东西的都是节点
>元素节点(HTML标签)
>文本节点(文字内容)
>注释节点(注释内容)
>文档节点(document)
每一种类型的节点都会有一些属性区分自己的特点和特征
-nodeType: 节点类型
-nodeName: 节点名称
-nodeValue: 节点值
```元素节点
nodeType:1
nodeType:大写标签名
nodeValue:null
```
``` 文本节点
nodeType:3
nodeName:"#text"
nodeValue:文本内容
在标准浏览器中,浏览器都会把空格,换行当作文本节点处理
```
``` 注释节点
nodeType:8
nodeName:"#comment"
nodeValue:注释内容
```
``` 文档节点
nodeType:9
nodeName:"#document"
nodeValue:null
### 描述节点关系的属性
" parentNode "
> 获取当前节点唯一的父亲节点
" childNodes "
> 获取当前元素的所有子节点
> -子节点:只获取儿子级别的
-所有:包含元素节点,文本节点等
" children "
> 获取当前元素所有的元素子节点
>在IE6-8中注释节点也当作元素节点来获取到,所有兼容性不好。
" previousSibling "
> 获取当前节点的上一个节点(获取的哥哥可能是元素也可能是文本等)
> previousElementSibling :获取上一个哥哥元素节点(不兼容IE8)
" nextSibling "
> 获取当前节点的下一个弟弟节点
> nextElementSibling: 下一个弟弟元素节点(不兼容IE8)
" firstChild "
> 获取当前元素的第一个子节点(可能是元素或文本等)
> firstElementChild 获取第一个元素节点
" lastChild "
> 获取当前元素的最后一个子节点
> lastElementChild 获取当前元素的最后一个子元素节点
```
// 需求一: 获取当前元素的所有元素子节点
// 基于children不兼容IE低版本浏览器(会把注释当作元素节点)
/*
* chikdren: 获取当前元素所有的元素子节点
* @parametet:
* curEle: [object]current elemrnt
* @return
* [array]all the element nodes
* by team on 2018
*/
function children(curEle){
var result = [],curEle = curEle.childNodes;
for(var i = 0;i<curEle.length;i++){
if(curEle[i].nodeType==1){
list.push(curEle[i])
}
}
return result;
}
console.log(children(course))
// 需求:获取当前元素的上一个哥哥元素节点
// > previousElementSibling不兼容
/* prev:获取当前元素的上一个哥哥元素节点
* @parameter
* curEle: [object]
* @return
* [object] last elder brother element
* by skl on 2019
*/
function prev(curEle){
//=》先找当前元素的哥哥节点,看是否为元素节点,不是基于哥哥找哥哥的上一个节点。。。一直找到元素节点或者没有哥哥了(说明我就是老大),则结束查找
var pre = curEle.previousSibling;
while(pre && pre.nodeType!==1){
/*
* pre && pre.nodeType!==1
* pre是验证还有木有,这样写代码有,没有pre是null
* pre.nodeType是验证是否为元素
*/
pre = pre.previousSibling;
}
return pre;
}
```
扩展:
next下一个弟弟元素节点,
prevAll获取所有哥哥元素节点,
nextAll获取所有弟弟元素节点
silbings获取所有兄弟节点,
index获取当前元素的索引...
### DOM增删该查
"
createElement
> 创建一个元素标签(元素对象)
> `document.createElement([标签名])`
appendChild
> 把一个元素对象插入到指定容器的末尾
> `[container].appendChild([newEle])`
insertBofore
> 把一个元素对象插入发哦指定容器中某一个元素标签之前
> `[container].insertBofore([newEle],[oldEle])`
cloneNode
> 把某一个节点进行克隆
> `[curEle].cloneNode()`: 浅克隆,只克隆当前标签
> `[curEle].cloneNode(true)`:深克隆,当前标签及其里面的内容都一起克隆了
removeChild
> 在指定容器中删除每一个元素
> `[container].removeChild([curEle])`
set/get/removeAttribute
设置/获取/删除 当前元素的某一个自定义属性值(两种方法)
···javascript
var oBox = document.getElementById('box');
// 1.=> 把当前元素作为一个对象,在对象对应的堆内存新增一个自定义属性
//增加
oBox.myIndex = 10;
//获取
console.log(oBox['myIndex'])
//删除
oBox.myIndex = null;
delete oBox.myIndex
// 2.=> 基于Attribute等DOM方法完成自定义属性的设置
// 设置
oBox.setAttribute('myColor','red');
// 获取
oBox.getAttribute('myColor');
// 删除
oBox.removeAttribute('myColor');
上下两张机制属于独立的运作机制,不能互相混淆使用
- 第一种是基于对象键值对操作方式,修改当前元素对象的堆内存空间来完成
- 第二种是直接修改页面中HTML标签的结构来完成的(此种方法设置的自定义属性可以在结构上呈现出来)
-基于setAttribute设置的自定义属性值都是字符串
···
"
### 案例
/*
* 需求:解析一个URL字符串问号传参和HASH
*/
// 解析a标签href
function queryURLParameter(str){
// 1.创建一个A标签,把需要解析的地址当作A标签的HREF赋值
var link = document.createElement('a');
link.href = str; //页面中不需要展示A,我们只是想要利用它的属性而已,所以无需添加到页面
// 2.A元素对象的HASH/SEarch两个属性分别存储了哈希值和参数值
var search = link.search.substr(1);
var hash = link.hash.substr(1);
// 3.分别解析出HASH和参数即可
var obj = {};
hash?obj.HASH=hash: null;
if(search){
console.log(search)
var list = search.split('&');
for(var i = 0;i<list.length;i++){
var arrChildlist = list[i].split('=')
obj[arrChildlist[0]] = arrChildlist[1]
}
}
return obj;
}
var str = 'https://www.baidu.com?lx=1&name=AA&age=1#teacher'
queryURLParameter(str)