DOM知识总结

DOM简介

文档对象模型(简称DOM),是W3C组织推荐的处理可扩展标记语言(HTML或XML)的标准==编程接口==,通过这些DOM接口可以改变网页的内容、结构、样式。

包括内容:

  • 文档:一个页面就是一个文档,DOM中使用document表示
  • 元素:页面中的==所有标签==都是元素,DOM中使用element表示
  • 节点:页面中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示

DOM把以上内容都看做是==对象==

获取页面元素

DOM在实际开发中主要用来操作元素

获取页面中元素可以使用以下几种方式:

1. 获取ID获取

getElementById()

1
2
3
4
5
6
7
<body>
<div id="box"></div>
<script>
var box = document.getElementById('box');
console.log(box); //获取的是box这个盒子
</script>
</body>
  • 文档是从上往下加载,所以script写到标签的下面
  • get获得 element元素 by通过 采用驼峰命名法
  • 参数id是大小写敏感的字符串
  • 返回的是一个元素对象
  • console.dir() 打印我们返回的元素对象,更好的查看里面的属性和方法

2. 根据标签名获取

getElementByTagName()

  • 可以返回带有指定标签的==对象的集合==,以==伪数组==的形式存储
  • 想要依次打印里面的元素对象可以采取数组遍历的方式
  • 如果页面中没有元素,返回的是空的伪数组的形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<body>
<ul>
<li>hello</li>
<li>hello</li>
<li>hello</li>
</ul>
</body>
<script>
var lis = document.getElementByTagName('li');
console.log(lis);
console.log(lis[0]);
//依次打印元素
for(var i = 0; i<lis.length; i++) {
console.log(lis[i]);
}
//element.getElementByTagName('标签名') 获得特定元素下的特定标签名的标签
//var ol = document.getElementByTagName('ol');
//console.log(ol[0].getElementByTagName('li'));
var ol = document.getElementById('ol');
console.log(ol.getElementByTagName('li'));
</script>

3. 通过HTML5新增的方法获取

1. getElementByClassName(“类名”)

根据==类名==返回元素对象集合

2. querySelector(“选择器”)

根据==指定选择器==返回==一个==元素对象

里面的选择器需要加符号 .box#nav

3. querySelectorAll(“选择器”)

根据==指定选择器==返回==所有==元素对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//
var boxs = document.getElementByClassName('box');
console.log(boxs);
//
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav');
console.log(nav);
var li = document.querySelector('li');
//
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);

4. 特殊元素获取

  • 获取body元素

    1
    document.body  //返回body元素
  • 获取html元素

    1
    document.documentElement  //返回html对象元素

1.

元素操作

DOM操作可以改变网页内容、结构和样式,可以利用DOM操作元素来改变元素里的内容、属性等

1. 修改元素内容

element.innerText

从起始位置到终止位置的内容,但会去除html标签。同时空格和换行也会去掉

element.innerHTML

起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行

innerText与innerHTML区别:

  • innerText不识别html标签(非标准),innerHTML识别html标签(W3C标准)
  • innerText去除空格和换行,innerHTML保留空格和换行

2. 修改元素属性

可以修改元素的属性,像元素的id、class、src、href、title等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
<div id="divid" class="divclass"></div>
<img src="image/1.jpg"alt=""title="hello">
<script>
var div = document.querySelector('div');
var img = document.querySelector('img');
console.log(div.id);
console.log(div.className);
div.id = "afterid";
div.className = "afterclass";
console.log(div.id);
console.log(div.className);
img.src = 'image/2.jpg';
img.title = 'morning';
</script>
</body>

3. 修改表单属性

修改表单的type、value、checked、selected、disabled属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<input type= "text"value= "请输入">
<button>提交</button>
<script>
//1.获取元素
var input = document.querySelector('input');
var button = document.querySelector('button');
//2.注册事件 处理程序
input.value = "after";
console.log(input.value);
button.onclick = function() {
input.innerHTML = '点击'
//value修改的是表单里面的值innerHTML修改的是普通盒子比如div标签里面的内容
input.value = '被点击'
this.disabled = true;
//如果想要某个表单被禁用 不能再点击 用disabled,当值为true时即表示禁用
//this指向的是事件函数的调用者button
}
</script>
</body>

4. 修改样式属性

通过JS修改元素的大小、颜色、位置等样式

1. element.style行内样式操作
2. element.className类名样式操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<div class="box"></div>
<script>
var box = document.querySelector('.box');
div.onclick = function() {
this.style.backgroundColor = 'purple';
this.style.width = '250px';
this.className = 'box change';
}
div.onblur = function() {
this.style.display = 'none';
}
</script>
</body>

注意:JS修改style样式操作,产生的是行内样式,且样式采用驼峰命名法 ,适用于修改样式较少的情况下,当修改样式较多时,修改类名,并重新用CSS写修改样式(如果要保留原先的类名,可以采用多类型选择器的方法命名)

5. 自定义属性

自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中

  • 设置元素的属性值

element.属性 = ‘值’;
element.setAttribute(‘属性’, ‘值’)

H5规定自定义属性打他-开头作为属性名并且赋值

1
2
<div data-index="1"></div>
element.setAttribute('data-index', 2);
  • 获取元素的属性值

element.属性 //获取属性值
element.getAttribute(‘属性’);

区别:

element.属性 获取==内置属性值==(元素本身自带的属性)

element.getAttribute(‘属性’); 主要获得==自定义的属性值==(标准)程序员自己添加的,称为index

  • removeAttribute移除自定义属性
1
2
3
4
5
6
7
8
9
10
11
12
13
var div = document.querySelector('div');
console.log(div.id);
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
//设置元素值
//(1)element.属性='值'
div.id = 'test';
div.className = 'navs';
//(2)element.setAttribute('属性', '值');主要针对自定义属性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer');
//class写的就是class,不是className
div.removeAttribute('index');

节点操作

1.节点概述

网页中所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示。HTML DOM树中所有节点均可通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建和删除

2. 节点操作的原因

获取元素的方法,逻辑性不强,并且获取元素很繁琐。而利用节点层级关系,我们可以利用元素间的父子或兄弟关系更简单的获取,逻辑性更强,缺点就是兼容性稍差。

3. 父子节点

1.Node.parentNode 获得Node节点的父节点

1
2
3
4
5
//1.父节点 parentNode
var erweima = document.querySelector('.erweima');
var box = document.querySelector('.box');
//得到的是离元素最近的父级节点 如果找不到父节点就返回null
console.log(erweima.parentNode);

2.Node.childNodes[n] 获得Node节点的第n+1个子节点(因为下标从0开始)

  • firstChild 第一个节点 不管是文本节点还是元素节点
  • firstElementChild 返回第一个==子元素节点==
1
2
3
4
5
6
7
console.log(ol.firstChild);
console.log(ol.lastChild);
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
//实际开发的写法 既没有兼容性问题又返回第一个子元素
console.log(ol.children[0]);
console.log(ol.children[ol.children.length-1]);
1
2
3
4
5
6
7
8
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
//1.子节点 childNodes 所有的子节点 包含元素节点、文本节点
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
console.log(ul.childNodes[1].nodeType);
//2.children 获取所有的子元素节点 也是最常用的方式
console.log(ul.children);

4. 兄弟节点

1.node.previousElementSibling 获得当前元素的上一个兄弟节点

2.node.nextElementSibling 获得当前元素的下一个兄弟节点

1
2
3
var box1 = document.querySelector('.box1');
var box2 = box1.previousElementSibling;
var box3 = box1.nextElementSibling;

找不到则返回null,包含所有的节点

5. 创建添加节点

  1. 创建节点

document.createElement(‘nodeName’)创建一个nodename节点

  1. 添加节点

1.Node.appendchild(child) 给父节点Node添加子节点child

添加到子节点列表==末尾==

2.Node.insertBefore(child,指定子节点) 给父节点的指定子节点之前添加一个子节点child

将一个节点添加到父节点的==指定子节点前面==

1
2
3
4
5
var li = document.creatElement('li');  // 创建新的节点元素
var ul = document.querySelector('ul');
ul.appendchild('li'); //添加节点元素
var li2 = document.createElement('li');
ul.insertBefore(li2,ul.children[0]);

想要页面添加一个新的元素:1. 创建元素 2. 添加元素

6. 删除节点

Node.removeChild(‘NodeName’) 删除父节点node的子节点

1
2
3
4
5
6
7
8
9
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
btn.onclick = function() {
if(ul.children.length == 0) {
this.disabled = true;
}else {
ul.removeChild(ul.children[0]);
}
}

7. 复制节点

Node.cloneNode(Boolean) 复制Node节点

如果括号里Boolean等于true,则为深拷贝(复制标签及里面的内容),如果不填或者为false,则为浅拷贝(只复制标签不复制里面的内容)

1
2
3
4
5
6
7
var box = document.querySelector('.box');
var copy = box.cloneNode(); //默认:浅拷贝
var deep = box.cloneNode(true); //深拷贝
var shallow = box.cloneNode(false); //浅拷贝
var ul = document.querySelector('ul');
var lili = ul.childreb[0].cloneNode(true);
ul.appendchild(lili);

8. 动态创建元素

  1. document.write()

    直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘

  2. element.innerHTML

    将内容写入某个DOM节点,不会导致页面全部重绘

    创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂

  3. document.createElement()

    创建多个元素效率稍低一点,但是结构更清晰

总结:不同浏览器下,==innerHTML效率要比createElement高==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//1.document.write()
var btn = document.querySelector('button');
btn.onclick = function() {
document.write('<div>123</div>');
}
//2.innerHTML
var inner = document.querySelector('.inner');
var arr = [];
for(var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
//3.document.createElement()
var create = document.querySelector('.create');
for(var i = 0; i <= 100; i++) {
var a = document.create('a');
create.appendchild(a);
}

==9.总结==

操作 方式
创建 1. document.write
2. innerHTML
3. createElement
1. appendChild
2. insertBefore
1.removeChild
主要修改dom的元素属性,dom元素的内容、属性,表单的值等
1. 修改元素属性:src、href、title等
2. 修改普通元素内容:innerHTML、innerText
3. 修改表单元素:value、type、disabled等
4. 修改元素样式:style、className
主要获取查询dom的元素
1. DOM提供的API方法:getElementByld、getElementsByTagName古老用法不太推荐
2. H5提供的新方法:querySelector、.querySelectorAll提倡
3. 利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)提倡
操作属性 主要针对于自定义属性
1. setAttribute:设置dom的属性值
2. getAttribute:得到dom的属性值
3. removeAttribute移除属性

事件处理

1. 事件基础

  1. 事件的组成:事件源、事件类型、事件处理程序(也称事件三要素)
  • 事件源 事件被触发的对象
1
var btn = document.getElementById('btn');
  • 事件类型 如何触发 什么事件
  • 事件处理程序 通过一个函数赋值的方式完成
1
2
3
btn.onclick = function() {
alert('hello');
}
  1. 执行事件的步骤

    • 获取事件源

    • 注册事件(绑定事件)

    • 添加事件处理程序(函数赋值)

2. 事件高级

1. 注册事件

给元素添加事件,称为注册事件或者绑定事件,有两种方式:==传统方式、方法监听注册方式==

1. 传统注册方式
  • 利用on开头的事件,如onclick
  • 可以行内添加,如<button onclick="alert('hello world')"></button>
  • 可以封装函数,如btn.onclick()=function(){}
  • 特点:注册事件具有唯一性,同一个元素同一个事件只能设置一个处理函数,后注册的函数会覆盖前面注册的函数
2. 方法监听注册方式
  • W3C标准推荐方式
  • 通过 addEventListener(事件属性,事件处理,事件流) 方法实现
  • IE9之前不支持此方法,可使用attachEvent()代替
  • 特点:同一个元素同一个事件可以注册多个监听器,它们按照注册的顺序依次执行

eventTarget.addEventListener(type, listener, useCapture)

type:事件类型字符串,比如click、mouseover,注意==不带on==

listener:事件处理函数,事件反生是,会调研该监听函数

useCapture:可选参数,是一个布尔值,默认是false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var btns = document.querySelectorAll('button');
//1. 传统方式注册事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hello');
}//只会弹出hello
//2.事件监听注册事件
//(1)里面的事件类型是字符串 必须加引号 而且不带on
//(2)同一个元素 同一个事件可以添加多个监听器
btn[1].addEventlistener('click',function(){
alert(22);
})
btn[1].addEventListener('click',function(){
alert(33);
})
btn[1].addEvent('onclick',fn);
//这里的事件要加on 但函数不用加括号
function fn() {
alert(44);
}
2. 删除事件

1.传统注册方式
Event.οnclick=null;

2.方法监听注册方式
Event.removeEventListener(‘click’,fn);

1
2
3
4
5
6
7
8
9
10
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
divs[0].onclick = null; //传统方式删除事件
}
div[1].addEventListener('click', fn)
function fn() {
alert(22);
divs[1].removeEventListener('click',fn);
}
3. DOM事件流

事件流描述的是从页面中接收事件的顺序

事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流

DOM事件流分为3个阶段:

  1. 捕获阶段
  2. 当前目标阶段
  3. 冒泡阶段

事件捕获:网景最早提出,由DOM==最顶层节点开始==,然后逐级向下传播到最具体的元素接收的过程

事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程

1
2
3
4
5
6
7
8
9
10
11
//1.JS代码中只能执行捕获或者冒泡其中的一个阶段
//2.onclick和attachEvent(ie)只能得到冒泡阶段
//3.捕获阶段 如果addEventlistener第三个参数是true 那么则处于捕获阶段 document->html->body->father->son
var son = document.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
},true);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
},true)

1. 在实际开发中很少使用事件捕获,更关注事件冒泡

2.有些事件是没有冒泡的,比如onblur、onfocus、onmouseenter、onmouseleave

4. 事件对象
  • event就是一个事件对象 写到监听函数的小括号里面 当形参来看
  • 事件对象只有有了事件才会存在,是系统自动创建的,不需要我们传递参数
  • 事件对象 是事件的一系列相关数据的集合,跟事件的状态,比如键盘按键状态、鼠标的位置、鼠标按钮的状态

​ 简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,他有很多属性和方法

  • 这个事件对象也可以自己命名 比如event、e(最常用)
  • 事件对象也有兼容性问题 通过Windows.event兼容性的写法 e = e|| window.event;
1
2
3
4
5
6
7
8
var div = document.querySelector('.div');
div.onclick = finction(e) {
console.log(e);
console.log(window.event);
e = e || window.event;
}
//div.addEventListener('click'. function(event) {})
//div.onclick = function(event) {}
事件对象属性方法 说明
e.target 返回触发事件的对象 (标准)
e.srcElement 返回触发事件的对象 (非标准ie678使用)
e.type 返回事件的类型 比如click mouseover不带on
e.cancelBubble 该属性阻止冒泡 (非标准ie678使用)
e.returnValue 该属性阻止默认事件 (非标准)如不让链接跳转
e.preventDefault() 该属性阻止默认事件 (标准)如不让链接跳转
e.stopPropagation() 阻止冒泡 (标准)
1
2
3
4
5
6
7
8
9
10
11
12
//1. e.target 返回的是触发事件的对象||this返回的是绑定事件的对象
//区别:e.target点击了那个元素 就返回那个元素||this返回绑定事件的元素
var div = document.querySelector('.div');
div.addEvebtListener('click', function(e) {
console.log(e.target);
console.log(this);
})
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
console.log(this);
console.log(e.target);
})

①阻止默认行为

1
2
3
4
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); //阻止默认行为
})

②阻止事件冒泡

标准写法:利用事件对象里面的stopPropagation()方法

e.stopPropagation()

非标准写法:IE678利用事件对象cancelBubble属性

1
2
3
4
5
6
7
8
9
var father = document.querySelector('.father');
var son = father.children[0];
father.addElementListener('click', function() {
alert('father');
})
son.addElementListener('click', function() {
alert('son');
e.stopPropagation();
})

③事件委托

原理:不是每个子节点单独设置事件监听器,而是将事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点

以上案例:给ul注册点击事件,然后利用事件对象的target来找到当前点击的Ii,因为点击Ii,事件会冒泡到ul上有注册事件,就会触发事件监听器

作用:只操作了一次DOM,提高了程序的性能

5. 常用鼠标事件
鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发

==使用监听注册时去掉前面 ‘on’==

  1. 禁止鼠标右键菜单

contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单

document.addEventListener(‘contextmenu’, function(e) {

​ e.preventDefault();

})

  1. 禁止鼠标选中

document.addEventListener(‘selectstart’, function(e) {

​ e.preventDefault();

})

  1. 获得鼠标坐标
鼠标事件 触发条件
e.clientX 返回浏览器相对于浏览器窗口可视区的X坐标
e.clientY 返回浏览器相对于浏览器窗口可视区的Y坐标
e.pageX 返回鼠标相对于文档页面的X坐标 (IE9+支持)
e.pageY 返回鼠标相对于文档页面的Y坐标 (IE9+支持)
e.screenX 返回鼠标相对于电脑屏幕的X坐标
e.screenY 返回鼠标相对于电脑屏幕的Y坐标
  1. 常用键盘事件
键盘事件 触发条件
onkeyup 某个键盘按键被松开时触发
onkeydown 某个键盘按键被按下时触发
onkeypress 某个键盘按键被按下时触发 但是它不识别功能键 ctrl shift等

当按下一个按键再松开时,三个事件的执行顺序依次为:
onkeydown ->onkeypress->onkeyup

==使用监听注册时去掉前面 ‘on’==

键盘事件对象属性:keyCode

说明:返回该键的ASCII值

注意:

  1. keyup和keydown事件不区分字母大小写,如a和A得到的都是65
  2. keypress事件区分字母大小写