01 前言
BOM(Browser Object Model)和 DOM(Document Object Model)是前端开发中不可或缺的两个概念。BOM 提供了访问浏览器窗口和窗口内的文档等功能,而 DOM 则提供了操作 HTML 和 XML 文档的接口。深入理解 BOM 和 DOM 对于开发出高效、优质的网页应用程序至关重要。
本文将承接上文对于BOM和DOM的一些具体操作,也就是常用技巧的汇总。深入讲解 BOM 和 DOM 的使用方法,包括但不限于 BOM 对象、BOM 事件、DOM 节点和 DOM 事件等内容。无论您是初学者还是有经验的开发者,本文都将为您提供一份全面的参考资料。
02 DOM
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。
通过这个对象模型,JavaScript 获得创建动态 HTML 的所有力量:
- JavaScript 能改变页面中的所有 HTML 元素
- JavaScript 能改变页面中的所有 HTML 属性
- JavaScript 能改变页面中的所有 CSS 样式
- JavaScript 能删除已有的 HTML 元素和属性
- JavaScript 能添加新的 HTML 元素和属性
- JavaScript 能对页面中所有已有的 HTML 事件作出反应
- JavaScript 能在页面中创建新的 HTML 事件
换言之:HTML DOM 是关于如何获取、更改、添加或删除 HTML 元素的标准。
2.1 查找元素
常用查找元素的方法,这里是对上文的一个补充和提示。
方法 | 描述 |
---|---|
document.getElementById(id) | 通过元素 id 来查找元素。 |
document.getElementsByTagName(name) | 通过标签名来查找元素。 |
document.getElementsByClassName(name) | 通过类名来查找元素。 |
document.querySelector(CSS选择器) | 通过CSS选择器选择一个元素。 |
document.querySelectorAll(CSS选择器) | 通过CSS选择器选择多个元素。 |
2.2 读取HTML
方法 | 描述 |
---|---|
元素节点.innerText | 获取 HTML 元素的 inner Text。 |
元素节点.innerHTML | 获取 HTML 元素的 inner HTML。 |
元素节点.属性 | 获取 HTML 元素的属性值。 |
元素节点.getAttribute(attribute) | 获取 HTML 元素的属性值。 |
元素节点.style.样式 | 获取 HTML 元素的行内样式值。 |
其他补充:
操作 | 描述 |
---|---|
document.getElementById(id) | 返回具有指定ID的元素对象。 |
document.getElementsByTagName(name) | 返回具有指定标签名称的元素对象的数组。 |
element.innerHTML | 获取或设置元素的HTML内容。 |
element.style.property | 获取或设置元素的样式属性。 |
element.setAttribute(name, value) | 设置元素的属性值。 |
element.getAttribute(name) | 返回元素的属性值。 |
element.appendChild(node) | 将指定节点添加到元素的子节点列表的末尾。 |
element.removeChild(node) | 从元素的子节点列表中删除指定的子节点。 |
element.addEventListener(event, function) | 添加事件监听器。 |
element.classList.add(class) | 将类名添加到元素的类属性中。 |
element.classList.remove(class) | 从元素的类属性中删除类名。 |
element.classList.toggle(class) | 在元素的类属性中切换类名。 |
element.classList.contains(class) | 检查元素的类属性中是否包含指定的类名。 |
这些DOM操作都可以用于访问和操作HTML文档中的元素和内容,使得开发者能够动态地更新和改变HTML页面的内容和样式。
2.2.1 浏览器读取默认样式
注意:通过style属性设置和读取的都是内联样式,无法读取样式表中的样式或者说正在应用的样式,如果想要读取当前正在应用的样式属性我们可以使用
元素.currentStyle.样式名
来获取元素的当前显示的样式,它可以用来读取当前元素正在显示的样式,如果当前元素没有设置该样式,则获取它的默认值,但是currentStyle只有IE浏览器支持,其它的浏览器都不支持。
在其它浏览器中可以使用getComputedStyle()
这个方法来获取元素当前的样式,这个方法是window的方法,可以直接使用,但是需要两个参数:
- 第一个参数:要获取样式的元素
- 第二个参数:可以传递一个伪元素,一般都传null
该方法会返回一个对象,对象中封装了当前元素对应的样式,可以通过 对象.样式名
来读取样式,如果获取的样式没有设置,则会获取到真实的值,而不是默认值。
比如:没有设置width,它不会获取到auto,而是一个长度,但是该方法不支持IE8及以下的浏览器。
通过currentStyle和getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改必须通过style属性,因此,我们可以写一个适配各个浏览器的读取元素样式的方法。
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
/*样式表的样式*/
#box {
width: 200px;
height: 200px;
background-color: green;
}
</style>
</head>
<body>
<div style="width: 100px;height: 100px;" id="box"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
/*通用的获取元素样式的方法*/
function getStyle(obj, name) {
if (window.getComputedStyle) {
//正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj, null)[name];
} else {
//IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}
}
var box = document.getElementById("box");
console.log(getStyle(box, "width"));
console.log(getStyle(box, "height"));
console.log(getStyle(box, "background-color"));
</script>
</body>
</html>
2.2.2 获取任意标签的文本内容
假设我们有一个 HTML 页面,其中有一个带有 ID 属性的 div 元素和一个带有 class 属性的 p 元素。我们可以使用 DOM 来获取这些元素的文本内容。
以下是获取任意标签的文本内容的案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a href="https://www.baidu.com" id="a">打开百度,你就知道!</a>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var a = document.getElementById("a");
console.log(getInnerText(a));
/*获取任意标签的内容*/
function getInnerText(element) {
// 判断浏览器是否支持textContent,如果支持,则使用textContent获取内容,否则使用innerText获取内容。
if(typeof element.textContent == "undefined") {
return element.innerText;
} else {
return element.textContent;
}
}
</script>
</body>
</html>
上面的代码首先使用 getElementById
方法获取 a 元素,并使用 textContent
属性或getInnerText
获取其文本内容,然后将其打印到控制台。这样,我们就可以使用 DOM 获取任意标签的文本内容了。
2.3 修改HTML
方法 | 描述 |
---|---|
元素节点.innerText = new text content | 改变元素的 inner Text。 |
元素节点.innerHTML = new html content | 改变元素的 inner HTML。 |
元素节点.属性 = new value | 改变 HTML 元素的属性值。 |
元素节点.setAttribute(attribute, value) | 改变 HTML 元素的属性值。 |
元素节点.style.样式 = new style | 改变 HTML 元素的行内样式值。 |
注意:改变样式只能使用.style,后续其他方法都是读取样式,或者修改HTML
2.3.1 insertAdjacentHTML
和insertAdjacentText
方法实现修改
注意:修改节点的内容除了常用的innerHTML和innerText之外,还有
insertAdjacentHTML
和insertAdjacentText
方法,可以在指定的地方插入内容。insertAdjacentText
方法与insertAdjacentHTML
方法类似,只不过是插入纯文本,参数相同。
注意事项:
- 这两个方法必须等文档加载好后才能执行,否则会出错。
- insertAdjacentText只能插入普通文本,insertAdjacentHTML插入html代码。
- 使用insertAdjacentHTML方法插入script脚本文件时,必须在script元素上定义defer属性。
- 使用insertAdjacentHTML方法插入html代码后,页面上的元素集合将发生变化。
- insertAdjacentHTML方法不适用于单个的空的元素标签(如img,input等)。
参数说明:
参数一:where:
- beforeBegin:插入到开始标签的前面
- beforeEnd:插入到结束标签的前面
- afterBegin:插入到开始标签的后面
- afterEnd:插入到结束标签的后面
参数二:
- html:一段html代码
- text:一段文本值
代码示例:
<!DOCTYPE html>
<html>
<head>
<title>DOM示例</title>
</head>
<body>
<p class="myPara">这是一个示例p元素。</p>
<div id="myDiv">这是一个示例div元素。</div>
<script>
// 使用insertAdjacentHTML添加狐妖小红娘的优酷视频超链接
document.body.insertAdjacentHTML('beforeend', '<p><a href="https://v.youku.com/v_show/id_XMTMzNzgyMzY5Ng==.html?spm=a2h1n.8251845.0.0" target="_blank">狐妖小红娘的优酷视频</a></p>');
// 使用insertAdjacentText添加狐妖小红娘的简介
var myPara = document.getElementsByClassName('myPara')[0];
myPara.insertAdjacentText('afterEnd', '以下是狐妖小红娘的简介:');
// 使用insertAdjacentElement添加狐妖小红娘的简介
var myDiv = document.getElementById('myDiv');
var introPara = document.createElement('p');
var introText = document.createTextNode('《狐妖小红娘》是一部描写狐妖与人类之间的爱情故事的动漫作品。');
introPara.appendChild(introText);
myDiv.insertAdjacentElement('beforeBegin', introPara);
</script>
</body>
</html>
2.3.2 编写一段兼容性代码,用来设置任意标签的文本内容
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a href="https://www.baidu.com" id="a">打开百度,你就知道!</a>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var a = document.getElementById("a");
setInnerText(a, "你要打开百度吗?");
console.log(getInnerText(a));
/*获取任意标签的内容*/
function getInnerText(element) {
// 判断浏览器是否支持textContent,如果支持,则使用textContent获取内容,否则使用innerText获取内容。
if (typeof element.textContent == "undefined") {
return element.innerText;
} else {
return element.textContent;
}
}
/*设置任意标签的内容*/
function setInnerText(element, text) {
// 判断浏览器是否支持textContent,如果支持,则使用textContent设置内容,否则使用innerText设置内容。
if (typeof element.textContent == "undefined") {
return element.innerText = text;
} else {
return element.textContent = text;
}
}
</script>
</body>
</html>
2.4 修改元素样式
方法 | 描述 |
---|---|
document.createElement(element) | 创建 HTML 元素节点。 |
document.createAttribute(attribute) | 创建 HTML 属性节点。 |
document.createTextNode(text) | 创建 HTML 文本节点。 |
元素节点.removeChild(element) | 删除 HTML 元素。 |
元素节点.appendChild(element) | 添加 HTML 元素。 |
元素节点.replaceChild(element) | 替换 HTML 元素。 |
元素节点.insertBefore(element) | 在指定的子节点前面插入新的子节点。 |
2.4.1兼容性修改样式
动态判断、添加、删除、切换样式,支持IE5-IE11,谷歌浏览器、火狐浏览器等
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
.b1 {
width: 100px;
height: 100px;
background-color: red;
}
.b2 {
width: 300px;
height: 300px;
background-color: yellow;
}
</style>
</head>
<body>
<button id="btn0">判断b2样式</button>
<button id="btn1">添加b2样式</button>
<button id="btn2">删除b2样式</button>
<button id="btn3">切换b2样式</button>
<br>
<br>
<div id="box" class="b1"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var btn0 = document.getElementById("btn0");
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var btn3 = document.getElementById("btn3");
var box = document.getElementById("box");
btn0.onclick = function () {
alert(hasClass(box, "b2"));
};
btn1.onclick = function () {
addClass(box, "b2");
};
btn2.onclick = function () {
removeClass(box, "b2");
};
btn3.onclick = function () {
toggleClass(box, "b2");
};
/*
* 判断一个元素中是否含有指定的class属性值
* 如果有该class,则返回true,没有则返回false
*/
function hasClass(obj, cn) {
var reg = new RegExp("\\b" + cn + "\\b");
return reg.test(obj.className);
}
/*
* 向一个元素中添加指定的class属性值
* 参数:
* obj 要添加class属性的元素
* cn 要添加的class值
*/
function addClass(obj, cn) {
// 检查obj中是否含有cn
if (!hasClass(obj, cn)) {
obj.className += " " + cn;
}
}
/*
* 删除一个元素中的指定的class属性
*/
function removeClass(obj, cn) {
var reg = new RegExp("\\b" + cn + "\\b");
obj.className = obj.className.replace(reg, "");
}
/*
* toggleClass可以用来切换一个类
* 如果元素中具有该类,则删除
* 如果元素中没有该类,则添加
*/
function toggleClass(obj, cn) {
// 判断obj中是否含有cn
if (hasClass(obj, cn)) {
// 存在,则删除
removeClass(obj, cn);
} else {
// 没有,则添加
addClass(obj, cn);
}
}
</script>
</body>
</html>
2.5 查找父子节点
下面是利用 DOM 树查找各种节点的常用函数和方法以及它们的返回值和用途的表格展示:
查找函数/方法 | 返回值 | 用途 |
---|---|---|
元素节点 getElementById | 单个元素 | 通过 ID 获取元素 |
getElementsByClassName | 元素集合 | 通过类名获取元素 |
getElementsByTagName | 元素集合 | 通过标签名获取元素 |
querySelector | 单个元素 | 通过选择器获取元素 |
querySelectorAll | 元素集合 | 通过选择器获取元素 |
文本节点 createTextNode | 文本节点 | 创建文本节点 |
nodeValue | 字符串 | 获取/设置节点的文本内容 |
属性节点 getAttribute | 字符串 | 获取元素的属性值 |
setAttribute | 无返回值 | 设置元素的属性值 |
removeAttribute | 无返回值 | 移除元素的属性 |
父节点 parentNode | 元素节点 | 获取元素的父元素 |
parentElement | 元素节点 | 获取元素的父元素 |
子节点 childNodes | 子节点集合 | 获取元素的所有子节点 |
children | 元素节点集合 | 获取元素的所有子元素 |
firstChild | 子节点 | 获取元素的第一个子节点 |
firstElementChild | 元素节点 | 获取元素的第一个子元素 |
lastChild | 子节点 | 获取元素的最后一个子节点 |
lastElementChild | 元素节点 | 获取元素的最后一个子元素 |
nextSibling | 兄弟节点 | 获取元素的下一个兄弟节点 |
nextElementSibling | 元素节点 | 获取元素的下一个兄弟元素 |
previousSibling | 兄弟节点 | 获取元素的上一个兄弟节点 |
previousElementSibling | 元素节点 | 获取元素的上一个兄弟元素 |
创建节点 createElement | 元素节点 | 创建新的元素节点 |
createAttribute | 属性节点 | 创建新的属性节点 |
createComment | 注释节点 | 创建新的注释节点 |
createDocumentFragment | 文档片段节点 | 创建新的文档片段节点 |
插入节点 appendChild | 子节点 | 将新的子节点添加到元素的子节点列表的末尾 |
insertBefore | 子节点 | 将新的子节点插入到指定位置之前 |
删除节点 removeChild | 子节点 | 从元素的子节点列表中删除一个子节点 |
replaceChild | 子节点 | 替换元素的子节点 |
remove | 无返回值 | 从其父元素中删除当前节点 |
使用这些函数和方法,我们可以在 DOM 树中找到并操作各种类型的节点。
2.5.1 兼容性方法
/*获取任意一个父级元素的第一个子元素*/
function getfirstElementChild(element) {
if(element.firstElementChild) {
return element.firstElementChild;
} else {
var node = element.firstChild;
while(node && node.nodeType != 1) {
node = node.nextSibling;
}
return node;
}
}
/*获取任意一个父级元素的最后一个子元素*/
function getLastElementChild(element) {
if(element.lastElementChild) {
return element.lastElementChild;
} else {
var node = element.lastChild;
while(node && node.nodeType != 1) {
node = node.previousSibling;
}
return node;
}
}
/*获取任意一个子元素的前一个兄弟元素*/
function getPreviousElementSibling(element) {
if(element.previousElementSibling) {
return element.previousElementSibling;
} else {
var node = element.previousSibling;
while(node && node.nodeType != 1) {
node = node.previousSibling;
}
return node;
}
}
/*获取任意一个子元素的后一个兄弟元素*/
function getNextElementSibling(element) {
if(element.nextElementSibling) {
return element.nextElementSibling;
} else {
var node = element.nextSibling;
while(node && node.nodeType != 1) {
node = node.nextSibling;
}
return node;
}
}
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<p>前面的P标签</p>
<b>加粗文本</b>
<a href="https://www.baidu.com" id="a">百度一下</a>
<i>斜体文本</i>
<p>最后的P标签</p>
</div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
/*第一个子元素*/
var firstNode = getfirstElementChild(document.getElementById("container"));
console.log(firstNode.innerHTML);
/*最后一个子元素*/
var lastNode = getLastElementChild(document.getElementById("container"));
console.log(lastNode.innerHTML);
/*指定元素的前一个子元素*/
var node1 = getPreviousElementSibling(document.getElementById("a"));
console.log(node1.innerHTML);
/*指定元素的后一个子元素*/
var node2 = getNextElementSibling(document.getElementById("a"));
console.log(node2.innerHTML);
/*获取任意一个父级元素的第一个子元素*/
function getfirstElementChild(element) {
if (element.firstElementChild) {
return element.firstElementChild;
} else {
var node = element.firstChild;
while (node && node.nodeType != 1) {
node = node.nextSibling;
}
return node;
}
}
/*获取任意一个父级元素的最后一个子元素*/
function getLastElementChild(element) {
if (element.lastElementChild) {
return element.lastElementChild;
} else {
var node = element.lastChild;
while (node && node.nodeType != 1) {
node = node.previousSibling;
}
return node;
}
}
/*获取任意一个子元素的前一个兄弟元素*/
function getPreviousElementSibling(element) {
if (element.previousElementSibling) {
return element.previousElementSibling;
} else {
var node = element.previousSibling;
while (node && node.nodeType != 1) {
node = node.previousSibling;
}
return node;
}
}
/*获取任意一个子元素的后一个兄弟元素*/
function getNextElementSibling(element) {
if (element.nextElementSibling) {
return element.nextElementSibling;
} else {
var node = element.nextSibling;
while (node && node.nodeType != 1) {
node = node.nextSibling;
}
return node;
}
}
</script>
</body>
</html>
03 dom文档事件流
3.1 事件简述
DOM 事件模型是指当网页中发生某些特定的事件时,浏览器会自动创建一个事件对象,并将该事件对象传递给相关的 JavaScript 代码,以便处理该事件。事件模型分为三个阶段:捕获阶段、目标阶段和冒泡阶段。
- 常见的 DOM 事件包括:
- 鼠标事件:click、dblclick、mousedown、mouseup、mousemove、mouseover、mouseout、mouseenter、mouseleave 等;
- 键盘事件:keydown、keyup、keypress 等;
- 表单事件:submit、reset、focus、blur、change 等;
- 窗口事件:load、unload、resize、scroll 等;
- 手机事件:touchstart、touchmove、touchend 等。
- DOM 事件处理的方式有两种:传统的事件处理方式和现代的事件处理方式。
传统的事件处理方式是在 HTML 元素中通过属性绑定事件处理函数,如:
<button onclick="alert('Hello World!')">点击我</button>
这种方式的缺点是不易于维护和扩展,因为代码和 HTML 元素紧密耦合在一起。
现代的事件处理方式是通过 JavaScript 代码动态地绑定事件处理函数,如:
const button = document.querySelector('button');
button.addEventListener('click', function() {
alert('Hello World!');
});
这种方式可以让代码和 HTML 元素分离,更易于维护和扩展。
- 事件处理函数的基本语法如下:
element.addEventListener(event, function, useCapture);
其中,element 是要绑定事件处理函数的 HTML 元素;event 是要绑定的事件名称,如 click、mousemove 等;function 是事件处理函数,可以是已经定义的函数或匿名函数;useCapture 是一个可选的布尔值,表示事件处理是否在捕获阶段执行,默认为 false,即在冒泡阶段执行。
事件处理函数中的 this 关键字指向触发事件的 HTML 元素,event 对象包含有关事件的详细信息,如事件类型、事件目标、事件发生的时间等。可以通过 event 对象的属性和方法获取这些信息,如 event.type、event.target、event.timeStamp 等。
- 除了使用
addEventListener
方法绑定事件处理函数之外,还可以使用removeEventListener
方法取消事件处理函数的绑定,如:
button.removeEventListener('click', handleClick);
其中,handleClick 是要取消绑定的事件处理函数。需要注意的是,在使用 removeEventListener 方法取消绑定时,要确保传入的事件处理函数和之前绑定的事件处理函数是同一个函数,否则无法取消绑定。
3.2 窗口事件
由窗口触发该事件 (同样适用于 标签):
属性 | 描述 |
---|---|
onblur | 当窗口失去焦点时运行脚本。 |
onfocus | 当窗口获得焦点时运行脚本。 |
onload | 当文档加载之后运行脚本。 |
onresize | 当调整窗口大小时运行脚本。 |
onstorage | 当 Web Storage 区域更新时(存储空间中的数据发生变化时)运行脚本。 |
3.2.1 标签失去焦点
案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>示例页面</title>
</head>
<body>
<h1>欢迎访问示例页面</h1>
<p>请输入您的姓名:</p>
<input type="text" id="myInput">
<script>
const myInput = document.getElementById('myInput');
myInput.addEventListener('blur', function() {
alert('您已离开该目标');
});
</script>
</body>
</html>
3.3 表单事件
表单事件在HTML表单中触发 (适用于所有 HTML 元素,但该HTML元素需在form表单内):
属性 | 描述 |
---|---|
onblur | 当元素失去焦点时运行脚本。 |
onfocus | 当元素获得焦点时运行脚本。 |
onchange | 当元素改变时运行脚本。 |
oninput | 当元素获得用户输入时运行脚本。 |
oninvalid | 当元素无效时运行脚本。 |
onselect | 当选取元素时运行脚本。 |
onsubmit | 当提交表单时运行脚本。 |
如果单击“submit”,则不填写文本字段,将发生警报消息。案例演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" id="text" required>
<input type="submit" value="submit">
</form>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var textInput = document.getElementById("text");
/* 如果单击“submit”,则不填写文本字段,将发生警报消息 */
textInput.oninvalid = function () {
console.log("请您完善表单内容!");
};
</script>
</body>
</html>
3.4 键盘事件
属性 | 描述 |
---|---|
onkeydown | 当按下按键时运行脚本。 |
onkeyup | 当松开按键时运行脚本。 |
onkeypress | 当按下并松开按键时运行脚本。 |
补充:
事件名称 | 触发条件 | 相关事件属性 |
---|---|---|
keydown | 按下任意键时触发 | event.key、event.code、event.keyCode、event.shiftKey、event.ctrlKey、event.altKey |
keyup | 松开任意键时触发 | event.key、event.code、event.keyCode、event.shiftKey、event.ctrlKey、event.altKey |
keypress | 按下并松开某个键时触发 | event.key、event.code、event.charCode |
其中,event.key 表示按下或松开的键的名称(例如,a、Shift、Enter),event.code 表示按下或松开的键的标准键码(例如,KeyA、ShiftLeft、Enter),event.keyCode 表示按下或松开的键的 ASCII 码(仅适用于部分键),event.shiftKey、event.ctrlKey、event.altKey 分别表示 Shift、Ctrl 和 Alt 键是否被按下。
注意:event.keyCode 已经被废弃,推荐使用 event.key 或 event.code。
以上是常用的键盘事件代码和相关事件属性。在实际应用中,可以根据需求选择相应的事件类型和事件属性来处理键盘事件。
3.4.1 键盘实现元素块的移动
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box" style="width: 100px;height: 100px;background: red;position: absolute;"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box = document.getElementById("box");
//为document绑定一个按键按下的事件
document.onkeydown = function (event) {
event = event || window.event;
// 定义移动速度
var speed = 10;
// 选择移动方向
switch (event.keyCode) {
case 37:
box.style.left = box.offsetLeft - speed + "px";
break;
case 39:
box.style.left = box.offsetLeft + speed + "px";
break;
case 38:
box.style.top = box.offsetTop - speed + "px";
break;
case 40:
box.style.top = box.offsetTop + speed + "px";
break;
}
};
</script>
</body>
</html>
3.5 鼠标事件
属性 | 描述 |
---|---|
onclick | 当单击鼠标时运行脚本。 |
ondblclick | 当双击鼠标时运行脚本。 |
onmousedown | 当按下鼠标按钮时运行脚本。 |
onmouseup | 当松开鼠标按钮时运行脚本。 |
onmousemove | 当鼠标指针移动时运行脚本。 |
onmouseover | 当鼠标指针移至元素之上时运行脚本,不可以阻止冒泡。 |
onmouseout | 当鼠标指针移出元素时运行脚本,不可以阻止冒泡。 |
onmouseenter | 当鼠标指针移至元素之上时运行脚本,可以阻止冒泡。 |
onmouseleave | 当鼠标指针移出元素时运行脚本,可以阻止冒泡。 |
onmousewheel | 当转动鼠标滚轮时运行脚本。 |
onscroll | 当滚动元素的滚动条时运行脚本。 |
3.5.1 鼠标实现拖曳元素快
案例演示2:编写一个通用的拖拽元素函数,创建两个div,进行拖拽演示,要求兼容IE8、火狐、谷歌等主流浏览器
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box1" style="width: 100px;height: 100px;background: red;position: absolute;"></div>
<div id="box2" style="width: 100px;height: 100px;background: green;position: absolute;"></div>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
drag(box1);
drag(box2);
/*
* 提取一个专门用来设置拖拽的函数
* 参数:开启拖拽的元素
*/
function drag(obj) {
//当鼠标在被拖拽元素上按下时,开始拖拽
obj.onmousedown = function (event) {
// 解决事件的兼容性问题
event = event || window.event;
// 设置obj捕获所有鼠标按下的事件
/**
* setCapture():
* 只有IE支持,但是在火狐中调用时不会报错,
* 而如果使用chrome调用,它也会报错
*/
obj.setCapture && obj.setCapture();
// obj的偏移量 鼠标.clentX - 元素.offsetLeft
// obj的偏移量 鼠标.clentY - 元素.offsetTop
var ol = event.clientX - obj.offsetLeft;
var ot = event.clientY - obj.offsetTop;
// 为document绑定一个鼠标移动事件
document.onmousemove = function (event) {
// 解决事件的兼容性问题
event = event || window.event;
// 当鼠标移动时被拖拽元素跟随鼠标移动
// 获取鼠标的坐标
var left = event.clientX - ol;
var top = event.clientY - ot;
// 修改obj的位置
obj.style.left = left + "px";
obj.style.top = top + "px";
};
// 为document绑定一个鼠标松开事件
document.onmouseup = function () {
// 取消document的onmousemove事件
document.onmousemove = null;
// 取消document的onmouseup事件
document.onmouseup = null;
// 当鼠标松开时,取消对事件的捕获
obj.releaseCapture && obj.releaseCapture();
};
/*
* 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
* 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
* 如果不希望发生这个行为,则可以通过return false来取消默认行为,
* 但是这招对IE8不起作用
*/
return false;
};
}
</script>
</body>
</html>
3.5.2 拖曳元素进行身份验证
实现拖拽验证身份信息的思路是,将需要拖拽的元素设置为可拖拽(draggable),然后在拖拽开始、拖拽过程和拖拽结束三个阶段分别监听相关事件,处理事件响应。具体步骤如下:
在 HTML 中定义需要拖拽的元素和放置元素;其中,id 为 draggable 的 div 元素是需要被拖拽的元素,设置 draggable 属性为 true 表示该元素可拖拽;id 为 droppable 的 div 元素是需要放置的元素。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>拖拽验证身份信息</title>
<style>
#draggable {
width: 100px;
height: 100px;
background-color: #6aa84f;
color: #fff;
text-align: center;
line-height: 100px;
cursor: move;
}
#droppable {
width: 200px;
height: 200px;
border: 2px dashed #ccc;
margin-top: 20px;
}
#droppable.droppable-hover {
background-color: #ddd;
}
#message {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #6aa84f;
color: #fff;
text-align: center;
padding: 20px;
font-size: 18px;
border-radius: 10px;
box-shadow: 2px 2px 2px #ccc;
}
</style>
</head>
<body>
<div id="draggable" draggable="true">拖拽我</div>
<div id="droppable">放置在此处</div>
<div id="message">身份验证成功!</div>
<script>
const draggable = document.getElementById('draggable');
const droppable = document.getElementById('droppable');
const message = document.getElementById('message');
let isDragging = false;
draggable.addEventListener('dragstart', function(event) {
isDragging = true;
event.dataTransfer.setData('text/plain', 'identity');
});
droppable.addEventListener('dragenter', function(event) {
if (isDragging) {
droppable.classList.add('droppable-hover');
}
});
droppable.addEventListener('dragover', function(event) {
event.preventDefault();
});
droppable.addEventListener('dragleave', function(event) {
droppable.classList.remove('droppable-hover');
});
droppable.addEventListener('drop', function(event) {
event.preventDefault();
droppable.classList.remove('droppable-hover');
const draggedItem = event.dataTransfer.getData('text/plain');
if (draggedItem === 'identity') {
message.style.display = 'block';
}
});
</script>
</body>
</html>
其中,dragstart、drag、dragend 分别表示拖拽开始、拖拽过程和拖拽结束;dragenter、dragover、dragleave 和 drop 分别表示拖拽元素进入放置区域、在放置区域中移动、离开放置区域和放置拖拽元素到目标元素中。
需要注意的是,在 dragover 事件中需要调用 event.preventDefault(),防止浏览器默认行为,使得拖拽操作可以被放置到目标元素中。
3.6 媒体事件
通过视频(videos),图像(images)或音频(audio) 触发该事件。
属性 | 描述 |
---|---|
onabort | 当发生中止事件时运行脚本。 |
oncanplay | 当媒介能够开始播放但可能因缓冲而需要停止时运行脚本。 |
oncanplaythrough | 当媒介能够无需因缓冲而停止即可播放至结尾时运行脚本。 |
ondurationchange | 当媒介长度改变时运行脚本。 |
onemptied | 当媒介资源元素突然为空时(网络错误、加载错误等)运行脚本。 |
onended | 当媒介已抵达结尾时运行脚本。 |
onerror | 当在元素加载期间发生错误时运行脚本。 |
onloadeddata | 当加载媒介数据时运行脚本。 |
onloadedmetadata | 当媒介元素的持续时间以及其它媒介数据已加载时运行脚本。 |
onloadstart | 当浏览器开始加载媒介数据时运行脚本。 |
onpause | 当媒介数据暂停时运行脚本。 |
onplay | 当媒介数据将要开始播放时运行脚本。 |
onplaying | 当媒介数据已开始播放时运行脚本。 |
onprogress | 当浏览器正在取媒介数据时运行脚本。 |
onratechange | 当媒介数据的播放速率改变时运行脚本。 |
onreadystatechange | 当就绪状态(ready-state)改变时运行脚本。 |
onseeked | 当媒介元素的定位属性不再为真且定位已结束时运行脚本。 |
onseeking | 当媒介元素的定位属性为真且定位已开始时运行脚本。 |
onstalled | 当取回媒介数据过程中(延迟)存在错误时运行脚本。 |
onsuspend | 当浏览器已在取媒介数据但在取回整个媒介文件之前停止时运行脚本。 |
ontimeupdate | 当媒介改变其播放位置时运行脚本。 |
onvolumechange | 当媒介改变音量亦或当音量被设置为静音时运行脚本。 |
onwaiting | 当媒介已停止播放但打算继续播放时运行脚本。 |
3.7 其它事件以及概念补充
属性 | 描述 |
---|---|
onshow | 当<menu> 元素在上下文显示时触发。 |
ontoggle | 当用户打开或关闭 <details> 元素时触发。 |
事件是 Web 应用程序中最重要的交互机制之一。当用户与网页进行交互时(比如点击按钮、拖拽元素、滚动页面等),浏览器会触发相应的事件,并将事件传递给网页的 JavaScript 代码处理。事件的处理方式包括事件绑定、事件委派、事件解绑等。下面是一些与事件处理相关的常用概念的解释:
- 事件捕获(Event Capturing):事件从文档根节点开始往下传递到目标元素之前,会先经过文档根节点、HTML 元素、body 元素、父元素等节点,这个过程称为事件捕获。事件捕获的处理函数会在目标元素的事件处理函数之前被触发。
- 事件目标(Event Target):事件目标是指用户与之交互的元素。例如,当用户点击一个按钮时,该按钮就是事件目标。
- 事件冒泡(Event Bubbling):事件从目标元素开始往上冒泡到文档根节点之前,会经过目标元素的父元素、body 元素、HTML 元素、文档根节点等节点,这个过程称为事件冒泡。
事件冒泡的处理函数会在目标元素的事件处理函数之后被触发。
- 事件委派(Event Delegation):事件委派是一种利用事件冒泡机制,在父元素上绑定事件处理函数,而不是在子元素上绑定事件处理函数。当子元素触发事件时,事件会冒泡到父元素,由父元素上的事件处理函数处理。这种方式可以减少事件处理函数的数量,提高页面性能。
- 事件绑定(Event Binding):事件绑定是指将事件处理函数绑定到一个元素上,当该元素触发相应的事件时,该事件处理函数会被执行。事件绑定通常使用
addEventListener()
方法实现。 - 事件传播(Event Propagation):事件传播是指事件从目标元素开始往上冒泡到文档根节点或者往下传递到子元素。事件传播包括事件捕获、事件目标、事件冒泡三个阶段。
- 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
- 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后在向内传播给后代元素。
- 事件解绑(Event Unbinding):事件解绑是指将事件处理函数从一个元素上移除,该元素不再响应相应的事件。事件解绑通常使用
removeEventListener()
方法实现。
以上是与事件处理相关的一些常用概念的解释。在实际应用中,根据需要选择不同的事件处理方式可以使页面交互更加灵活和高效。
3.7.1 阻止超链接跳转
代码演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
#div1 {
width: 200px;
height: 200px;
background: pink;
}
#div2 {
width: 100px;
height: 100px;
background: coral;
}
</style>
</head>
<body>
<a href="https://www.baidu.com" id="a">打开百度,你就知道!</a>
<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
var a = document.getElementById("a");
// 为a绑定单击事件
a.onclick = function () {
stopDefault();
};
// 阻止浏览器的默认行为
function stopDefault(event) {
if (event && event.preventDefault) {
// 阻止默认浏览器动作(W3C)
event.preventDefault();
} else {
// IE中阻止函数器默认动作的方式
window.event.returnValue = false;
}
return false;
}
</script>
</body>
</html>
04 BOM树
4.1 BOM模型
浏览器对象模型(BOM)可以使我们通过JS来操作浏览器,在BOM中为我们提供了一组对象,用来完成对浏览器的操作,常见的BOM对象如下:
- Window:代表的是整个浏览器的窗口,同时window也是网页中的全局对象
- Navigator:代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
- Location:代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
- History:代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录,由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页,而且该操作只在当次访问时有效
- Screen:代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息
4.2 常用的一些脚本操作
操作 | 描述 |
---|---|
window.open() | 打开新窗口或标签页。 |
window.close() | 关闭当前窗口或标签页。 |
window.location.href | 获取或设置当前窗口的 URL。 |
window.history.back() | 返回上一页。 |
window.history.forward() | 前往下一页。 |
window.navigator.userAgent | 获取用户代理信息。 |
window.navigator.cookieEnabled | 判断浏览器是否启用 cookie。 |
window.screen.width | 获取屏幕宽度。 |
window.screen.height | 获取屏幕高度。 |
window.document.cookie | 获取或设置当前窗口的 cookie。 |
注意:上述表格中仅列出了常用的一些操作,具体的应用还需要根据具体需求进行选择。剩下的平时也不太用的上,这里不做赘述。