【JavaScript】JS中的文档对象模型DOM
文档对象模型 DOM
一、基本概念
01. DOM概述
- DOM:Document Object Model,文档对象模型
- 是W3C组织定义的编程接口,通过这些
DOM
接口可以改变网页的内容、结构和样式 - DOM树:
- 文档:一个页面就是一个文档
- 元素:页面中的所有标签都属于元素
- 节点:网页中的所有内容都属于节点
- 针对元素的操作:创建、增、删、改、查、属性操作、事件操作
02. 基本要求
-
能够说出什么是DOM
-
能够获取页面元素能够给元素注册事件
-
能够操作DOM元素的属性
-
能够创建元素
-
能够操作DOM节点
-
能够写出元素注册事件的两种方式能够说出删除事件的两种方式
-
能够说出DOM事件流的三个阶段
-
能够利用事件对象完成跟随鼠标案例
-
能够封装阻止冒泡的兼容性函数
-
能够说出事件委托的原理
-
能够说出常用的鼠标和键盘事件
二、【获取元素】的几种方法~~~
获取DOM元素后,返回的是一个对象
01. 根据ID获取元素
-
document.getElementById(" ");
(ID
是唯一的,所以是Element
)<div id="time"> 2020-10-10 </div> <div class="animal"> Dog </div>
var time = document.getElementById("time");
02. 根据标签名获取元素
-
document.getElementsByTagName(" ");
(标签名可以有多个,所以是Elements
)var tagName = document.getElementsByTagName("div");
- 获取的是元素对象的集合
- 获取过来的元素:以伪数组的形式存储(不管元素是:一个、多个、没有,都是伪数组)
-
element.getElementsByTagName(" ");
var li = element.getElementsByTagName("ol"); //获取 ol 中的子元素 li
- 获取指定父元素内部的子元素
- 【注意】父元素必须是单个对象、是唯一的,即必须指明是哪一个元素对象
03. 根据class获取元素(H5新增)
-
document.getElementsByClassName(" ");
var animal = document.getElementsByClassName("animal");
04. 根据选择器获取元素(H5新增)
【注意】这里的选择器同CSS选择器使用方法一样,类名和id名都需要加符号
-
doucument.querySelector(" ");
只会返回指定选择器的第一个元素对象
var animal = document.querySelector(".animal"); //返回第一个,元素类名为 animal 的,元素
-
doucument.querySelectorAll(" ");
可以返回指定选择器里的所有元素对象
var div = doucument.querySelectorAll("div"); //返回所有div标签元素
05. 获取body和HTML元素
- 获取body元素:
document.body
- 获取HTML元素:
document.documentElement
三、如何【改变元素】?
01. 改变元素内容
(1)innerText
- 不识别HTML标签
- 在读取内容时,会跳过空格、换行、HTML标签
- 在写入内容时,会将**HTML标签(如果有)**一起写入
var p = document.querySelector("p"); // <p> 没有变化<span>还是没有</span> </P>
//在读取内容时,会跳过元素内部的HTML标签、空格、换行
p.innerText;
//输出结果:没有变化 还是没有
//在写入内容时,会把HTML标签 一起写入内容中
p.innerText("<strong>改变内容</strong>");
//输出结果:<strong>改变内容</strong>
(2)innerHTML
- 可识别HTMl标签
- 在读取内容时,会保留页面原有的空格、换行、标签
- 在写入内容时,会应用HTMl标签(如果有)
var p = document.querySelector("p"); // <p> 没有变化<span>还是没有</span> </P>
//在读取内容时,会将元素内部的HTML标签、空格、换行一起显示出来
p.innerHTML;
// 输出结果:没有变化<span>还是没有</span>
//在写入内容时,会识别到 HTML 标签并应用
p.innerHTML("<strong>改变内容</strong>");
// 输出结果(加粗的):改变内容
(3)其它
- 【注意】表单元素
form
里面的内容是通过元素属性更改的!!!
02. 改变元素属性
(1)内置属性获取
-
element.属性名
主要获取内置属性,自定义属性无法通过这种方式获取
element.属性名 = “属性值”;
var img = document.getElementById("image"); img.src = "url"; img.title = "new_title";
(2)自定义属性获取
-
(a)兼容性获取:
-
element.getAttribute("属性名");
主要获取自定义属性
-
element.setAttribute("属性名","属性值");
设置自定义属性
-
element.removeAttribute("属性名");
-
-
(b)H5新增:
H5新增的规定,将以
data-
开头的属性名作为自定义属性-
element.dataset.属性名
:获取属性,适用于以data-
开头的自定义属性,属性名是data-
后面的值这个方法只能获取以
data-
开头的,dataset
是一个集合,里面存放了所有以data-
开头的自定义属性 -
如果属性有多个
-
连接的单词,【需要注意】,在获取时,从第二个-
开始,需要驼峰命名<div data-index="1" data-last-name="demo"> </div>
var div = document.querySelector("div"); //获取 data-index 属性 div.dataset.index; //获取 data-last-name 属性,驼峰命名 div.dataset.lastName;
-
03. 改变样式属性
element.style
对元素的行内样式进行操作
【注意】:如果样式没有写在行内,是无法通过这种方式获取到的
-
使用方法:+
.属性
注意属性名是驼峰命名法,且没有分隔符
element.style.backgroundColor = " "; element.style.fontSize = "";
-
element.className
对样式文件中的类名样式进行操作
-
改变当前元素的类名,注意会覆盖原先的类名
-
可通过拼接字符串的方式添加,避免覆盖
element.className += " newClassName"; //注意要加空格
-
运用:精灵图的实现方法
for
循环遍历,改变backgroundPosition
的属性值
四、如何【操作元素】?
01. 获取元素的另一种方法——利用节点层级关系获取元素
页面中所有内容都是节点
-
(1)基本属性:
-
nodeType
、nodeName
、nodeValue
:节点类型、节点名称、节点值元素节点:
nodeType
为1属性节点:
nodeType
为2文本节点:
nodeType
为3(文本节点包括文字、空格、换行等)
-
-
(2)父级节点:
parentNode
得到离元素最近的父级节点,如果没有则返回
null
-
(3)子级节点:
childNodes
获得所有子节点,包含元素节点、文本节点
children
获取所有的子元素节点
firstChild
和lastChild
获取第一个(最后一个)子节点,不管是文本节点还是元素节点
firstElementChild
和lastElementChild
获取第一个(最后一个)子元素节点,有兼容性问题 ,IE9以上才支持
parentNode.children[0]
和parentNode.children[parentNode.children.length - 1]
返回第一个(最后一个)子元素,没有兼容性问题
parentNode.children
返回的是一个伪数组,parentNode.children.length - 1
:表示最后一个子元素 -
(4)兄弟节点:
nextSibling
和previousSibling
获取下一个(上一个)兄弟节点,包含元素节点或者文本节点等等
nextElementSibling
和previousElementSibling
获取下一个(上一个)兄弟元素节点,兼容性问题,IE9以上才支持
- 解决兼容性问题:自己封装一个函数
通过判断
nodeType
值,使用第一种方法实现
02. 动态操作元素节点
(1)创建元素节点
-
document.createElement(" ");
动态创建元素节点
(2)添加元素节点
-
parentNode.appendChild("child");
在父元素
parenrNode
的末尾,追加一个子元素child
-
parentNode.insertBefore("child", "指定元素");
在父元素
parenrNode
中,将子元素child
添加到指定的其它子元素的前面
(3)删除元素节点
parentNode.removeChild("child");
(4)复制元素节点
-
node.cloneNode();
返回调用该方法的节点的一个副本
如果括号为空,或者
false
,则为 浅拷贝 ,只复制标签不复制里面的内容如果括号为
true
,则为 深拷贝 ,会同时复制标签和里面的内容
03.【拓展】——三种动态创建元素方法的区别
document.write
、element.innerHTML
、document.createElement()
(1)关于document.write()
document.write
是直接将内容写入页面的内容流,- 如果是在文档流执行完毕后,执行
document.write
,则会导致页面内容全部重绘
(2)关于element.innerHTML
- 创建多个元素的效率高,但结构稍微复杂
- 但通过拼接字符串的方法添加元素到页面中效率很低(字符串的不可变性)
- 因此,可以通过**数组的方法
push()
**添加元素,效率最高
(3)关于document.createElement()
- 创建多个元素的效率低,但结构更清晰
- 通过
appenChild()
直接追加子元素到父元素末尾,效率高
五、关于页面元素的【事件】
01.基本概念
(1)基本事件组成
- 事件三要素:
- 事件源
- 被触发事件的对象
- 事件类型
- 如何触发事件,如:点击、滑过、键盘输入等
- 事件处理程序
- 完成什么事件
- 事件源
- 关于
this
this
指向的是事件函数的调用者
(2)基本事件执行过程
//1. 首先获取事件源元素
var btn = document.getElementById("btn");
//2. 然后 绑定事件(注册事件)
//3. 最后添加事件处理程序
div.onclick = function(){
alert("触发事件");
}
02. 元素注册事件的两种方式
(1)传统注册方式
- 利用
on
开头的事件,如:onclick
- 唯一性:同一个元素的同一个事件只能设置一个处理函数,最后注册的处理函数会覆盖前面注册的处理函数
(2)addEventListener事件监听
-
(a)语法结构
-
eventTarget.addEventListener(type, listener, useCapture);
- 将指定的监听器注册到
eventTarget
(目标对象)上 type
:事件类型字符串,如click
、mousemover
listener
:事件处理函数,事件发生时,会调用该监听函数useCapture
:可选参数,是一个布尔值,默认false
- 将指定的监听器注册到
-
(b)注册事件
eventTarget.addEventListener("type",function);
//为目标函数绑定 type 事件,该事件的处理函数是 function
03. 删除事件的方式
(1)传统方式删除事件
eventTarget.onclick = null
(2)removeEventListener删除事件
-
eventTarget.removeListener
eventTarget.removeListener("type",function); //移除目标对象的 type 事件,该事件绑定 function 处理函数
04. DOM事件流
(1)基本概念
-
事件流是指:从页面中接收时间的顺序
- 事件发生时,会在元素节点之间,按照特定的顺序传播,这个传播过程即DOM事件流
(2)阶段概述
(a)捕获阶段
-
从 DOM 最顶层的节点开始,然后逐级向下传播,到目标元素接收的过程
-
在逐级向下传播(沉底)中,如果有祖先元素绑定了相同类型事件(如点击事件),那么在触发目标后代元素事件时(点击后),会按照沉底的顺序(从上到下),依次触发事件(点击的事件)
(b)当前目标阶段
(c)冒泡阶段
-
事件开始时,从目标事件元素开始接收,然后逐级向上传播,到DOM最顶层的节点,这一过程
-
在逐级向上传播(冒泡)中,如果有祖先元素绑定了相同类型事件(如点击事件),那么在触发目标后代元素事件时(点击后),会按照冒泡的顺序(从下到上),依次触发事件(点击的事件)
(3)其它
onclick
等on
开头的事件,只会触发冒泡阶段- 【注意】
onblur
、onfocus
、onmouseenter
、onmouseleave
是没有冒泡阶段的
- 【注意】
addEventListener
可以触发多个阶段useCapture
:参数值为true
,则为捕获阶段useCapture
:参数值为false
,则为冒泡阶段
05. 事件对象
(1)概念
eventTarget.onclick = function(event){
};
-
事件发生后,跟事件相关的一系列信息数据集合,都会存放在这个事件对象
event
里面event
对象,代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态等
-
事件对象只有在有事件时才会存在,它是系统给自动创建的,即不需要传参进去
-
这个事件对象我们可以自己命名,如
event
、evt
、e
-
事件对象的兼容性问题
-
IE6、7、8,只会识别
window.event
兼容:
e = e || window.event;
-
(2)事件对象的常用属性和方法
-
e.target
:返回触发事件的对象(谁触发的事件,就返回谁)this
:返回的是绑定事件的对象(谁绑定的事件,就返回谁)
-
返回触发事件的类型
e.type
-
(a)阻止默认事件
-
高版本:
e.preventDefault()
: -
低版本(IE6、7、8):
e.returnValue
a.onclick = function(e) { // 普通浏览器 e.preventDefault(); 方法 e.preventDefault(); // 低版本浏览器 ie678 returnValue 属性 e.returnValue; // 我们可以利用return false 也能阻止默认行为 // 没有兼容性问题 return false; }
-
-
(b)阻止事件冒泡
-
标准写法:
e.stopPropagation()
-
非标准写法:
e.cancelBubble = true
if(e && e.stopPropagation){ e.stopPropagation(); }else{ window.event.cancelBubble = true; }
-
(3) 事件委托(代理、委派)
-
不需要给每个子节点单独设置事件监听器,而是把事件监听器设置再其父节点上,即把事件委托给了父节点
因为事件冒泡,点击子节点后,事件会冒泡到父节点上,同样会触发事件,然后可以通过
e.target
找到是哪一个子节点触发的事件(点击了谁)
事件委托的作用:只操作了一次DOM
06. 鼠标事件
(1)基本事件
-
onclick
:鼠标点击事件 -
onfocus
:获得焦点事件 -
onblur
:失去焦点事件 -
onmouseover
:鼠标经过事件- 经过子元素也会触发父元素的事件
-
onmouseenter
:鼠标经过事件(不会冒泡)- 只有经过盒子本身才触发
-
onmouseout
:鼠标离开事件- 经过子元素也会触发父元素的事件
-
onmouseleave
:鼠标离开事件(不会冒泡)- 只有经过盒子本身才触发
-
阻止链接跳转
<a href="javascript:void(0);"> 点击不跳转 </a> <a href="javascript:;"> 点击不跳转 </a>
-
禁用鼠标右键菜单:
contextmenu
e.addEventListener("contextmenu",function(e){ e.preventDefault(); });
-
禁止鼠标选中:
selectstart
e.addEventListener("selectstart",function(e){ e.preventDefault(); });
(2)鼠标事件对象
-
鼠标坐标
-
e.clientX
和e.clientY
得到鼠标相对于
client
可视窗口区域的坐标 -
e.pageX
和e.pageY
————(主要)得到鼠标相对于页面文档的坐标
-
e.screenX
和e.screenY
得到鼠标相对于电脑屏幕的坐标
-
-
鼠标移动
-
mousemove
只要鼠标移动,就触发事件
document.addEventListener('mousemove', function(e) { console.log("X坐标:"+e.pageX+",Y坐标:"+e.pageY); });
-
07. 键盘事件
(1)基本事件
-
keyup
:按键弹起的时候触发 ,松开键盘时只触发一次 -
keydown
:按键按下的时候触发,可识别功能键- 按下不松开会一直触发
-
keypress
:按键按下的时候触发,不可识别功能键,如ctrl
、shift
、 左右箭头等键盘事件的响应顺序:keydown → keypress → keyup
【注意】三者的区别与应用场景
(2) 键盘事件对象
-
e.keycode
:返回对应按键的ASCII码值可以判断用户按下了哪一个键
-
keyup
、keydown
不区分字母大小写,且以大写状态显示键值 -
keypress
可以区分字母大小写
-