写在前面

DOM的全称是Document Object Model(文档对象模型),是浏览器提供给JS用来操作整个html页面的元素的,在JS中通过window.document语句获取,由于是挂在window上的全局变量,因此可以省略window,直接document获取,基本原理就是浏览器将整个网页抽象成一个DOM,并通过树的数据结构划分页面元素。

1. DOM获取的元素的原型链

显然,根据浏览器提供的DOM接口可以获取到html页面的元素,获取到的元素很显然是一个对象,拥有很多自身属性和公有属性,搞清楚共有属性,那就需要搞清楚该元素的原型链,以一个DOM获取到的div元素的原型链展示,具体如下:

1)第一层原型是HTMLDivElement.prototype

里面是所有div元素共有的属性

2)第二层原型是HTMLElement.prototype

里面是所有HTML标签(也叫元素)共有的属性

3)第三层原型是Element.prototype

里面是浏览器支持的所有文件如HTML、XML、SVG标签(元素)的共有属性

4)第四层原型是Node.prototype

里面是所有节点共有的属性,节点包括浏览器支持的所有文件类型的标签、文字、注释等等。因此可知文字是节点,不是标签(也叫元素),注释也是节点。

5)第五层原型是EventTarget.prototype

里面是所有节点事件相关的属性,比较常用的属性是addEventListener。

6)第六层也是最后一 层原型是Object.prototype

终极原型,所有原型的祖先,到这就没了。

2. 获取页面元素的API

1.1 获取元素标签

需要兼容IE浏览器的必须用document.getElement(s)Byxxxxx语法,如果不必非要兼容IE浏览器,则一般使用 querySelector语法。

1))通过id获取

  1. window.idxx;
  2. idxx; //widow可省略,当id名为全局属性名关键字时不可用这种方法
  3. document.getElementById('idxxx');

2)通过class获取

  1. document.getElementsByClassName('classxxx'); //获得到的是一个class值为classxx的元素数组
  2. document.getElementsByClassName('classxxx')[i] //获得第i个元素

3)通过标签名获取

  1. document.getElementsByTagName('xxx'); //获得的是一个xxx标签元素数组,如div/span
  2. document.getElementsByTagName('xxx')[i]; //获得第i个元素

4)通过CSS选择器获取

根据css选择器字符串来选择一个元素(也叫标签)

  1. //语法
  2. element = baseElement.querySelector(selectors); //得到匹配条件的的第一个html元素
  3. elementList = baseElement.querySelectorAll(selectors); //得到匹配条件的所有html元素
  4. //document也是node节点,整个页面文档节点
  1. document.querySelector('#idxxx'); //通过id获得单个元素
  2. document.querySelectorAll('.classxxx')[i]; //通过class名获取元素数组
  3. document.querySelector('div > span:nth-child(2)'); //里面通过css的获取方法获取元素
  4. document.querySelectorAll('div > span:nth-child(2)'); //获取数组

1.2 获取特殊页面元素

1)获取html标签

  1. document.documentElement

2)获取head元素

  1. document.head

3)获取body元素

  1. document.body

5)获取窗口(窗口不是元素)

  1. window

6)获取所有元素(可用于判断浏览器类型)

  1. document.all //该值是一个falsy值
  2. //可用于判断当前浏览器是否是ie浏览器,该值在ie浏览器的ie11之前的版本中都是真,在其他浏览器是假,
  3. 在其他浏览器可以直接用,该语句可以判断是否是ie11之前的版本,新的ie11也是假了。
  4. if(document.all){
  5. console.log('ie11之前的ie版本');
  6. }
  7. else{
  8. console.log('ie11或Edge其他浏览器');
  9. }

3. 节点的增删改查

3.1 增

1)创建一个标签节点

  1. document.createElement('xxx');
  2. 例如 div = document.createElement('div');

2)创建一个文本节点

  1. document.createTextNode('stringxxx');
  2. 例如 text = document.createTextNode('这是个文本');

3)标签里插入文本

在JS中创建的节点默认是处在JS线程中,必须添加到html中的元素中才能生效,并且一个节点只能添加到一个元素中,不能一个节点添加到两个元素中,除非复制一份。

标签节点.appendChild('文本节点');

例如 div.appendChild(text);

  1. div.innerText = "这是个文本"
  2. div.textContent = "这是个文本" //这两种方法都可以改文本内容,textContent 可以获取所有后代的文本
  3. 但是不能是div.appendChild('这是个文本')

4)克隆节点

新节点 = 节点.cloneNode();

在新规范中,默认是浅克隆,只克隆节点本身,如果想把该节点的后代节点都克隆,需要手动设置 deep 值为 true

新节点 = 节点.cloneNode(true);

例如div2 = div.cloneNode();

3.2 删

1)旧方法,只能由父亲删除自己

这种方法需要先找到要删除元素的父元素,让其父元素删除它,这种删除只是将其从html中删除,节点还在内存中,可随时再添加,彻底删除的方法是将该删除节点置为空即可被内存管理回收。

要删除节点.parentNode.removeChild(要删除节点);

父元素节点.appendChild(删除的节点);

2)新方法,可自己删除自己,IE不支持

这种删除也只是将其从html中删除,节点还在内存中,可随时再添加,彻底删除的方法是将该删除节点置为空即可被内存管理回收。

要删除节点.remove();

父元素节点.appendChild(删除的节点);

3.3 改

1)改id

节点.id = '新id名';

2)改class

由于class是JS的关键字,所以不能直接节点.class修改,要如下方式:

旧方法

  1. 节点.className = '新cass名字';` //这样会完全覆盖原来的class属性值
  2. 节点.className += ' 新的class名'; //这样才会是添加class值,前面要有个空格

新方法

  1. //新方法的添加Class
  2. 节点.classList //可查看当前节点的所有class值
  3. 节点.classList.add('新的class名')
  4. 节点.classList.remove('class名')

3)改style

  1. 节点.style = 'width: 100px; color: red;' //一下改多个样式
  2. 节点.style.width = '100px'; //修改单个样式
  3. //JS不支持有中划线的key值,会被当成减号的,如background-color,则要以字符串形式表示或者改中划线为
  4. 首字母大写
  5. 节点.style['background-color'] = 'red';
  6. //or
  7. 节点.style.backgroundColor = 'red'; //或者首字母大写

4)改属性

  1. //可直接通过节点.属性名来修改,
  2. div.classList/a.href
  3. //但是有的属性这样获取会出错,如a.href,浏览器会补全路径,因此用如下方法:
  4. 节点.setAttribute('属性名','属性值');//该种方式最完整
  5. 节点.getAttribute('属性名'); //获得属性

5)改 data-* 属性

  1. //特殊地,该data-*开头的属性名的属性值时为
  2. 节点.dataset.* = 'xxx';

6)改文本内容

和增加文本内容是一样的语句

  1. div.innerText = "这是个文本"
  2. div.textContent = "这是个文本" //这两种方法都可以改文本内容

7)改HTML内容

  1. 节点.innerHTML = 'html语句'

8)改标签

改标签可以先用innerHTML将内容清空,再添加节点

  1. 节点.innerHTML = '';
  2. 节点.appendChild(节点);

9)改爸爸

  1. 新爸爸节点.appendChild(节点);
  2. //这样就可以改变父亲节点,因为一个节点只能添加到一个节点上,因此该节点会被从原父亲节点移除,加入新的父亲节点下

3.4 查(返回的是值)

1)查爸爸

  1. 节点.parentNode;
  2. //or
  3. 节点.parentElement;

2)查子代

  1. //查看所有孩子
  2. 节点.childNodes; //返回的是一个子节点数组,节点类型包括标签、文字、注释、多个回车或空格被html转化成
  3. 的一个空格也是其子节点
  4. //or
  5. 节点.children; //解决了childNodes的问题,是Element提供的,只计算元素,即标签节点
  6. //查看单个孩子
  7. 节点.firstChild; //查看第一个孩子
  8. 节点.lastChild; //查看最后一个孩子

3)查兄弟姐妹

DOM没有提供查找所有兄弟姐妹节点的API,可以通过查看其父亲节点的所有孩子节点,再排除掉自己,只提供了查看临近兄弟姐妹的API

  1. 节点.parentNode.childNodes; //不仅排除自己还要排除文本节点
  2. 节点.parentNode.children; //排除自己
  3. 节点.previousSibling; //临近的上个兄弟节点可能有文本节点
  4. 节点.nextSibling; //下个兄弟节点,可能有文本节点
  5. 节点.previousElementSibling; //上一个元素兄弟
  6. 节点.nextElementSibling; //下一个元素兄弟