给元素添加事件,称为注册事件或者绑定事件,注册事件有两种方式:传统方式和方法监听注册方式
传统注册方式 :
方法监听注册方式:
eventTarget.addEventListener(type, listener[, useCapture])
eventTarget.addEventListener()方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
下面是一个代码例子:
const button = document.querySelector('button');
button.addEventListener('click', () => {
console.log('第一个事件被触发!');
});
button.addEventListener('mouseover', () => {
console.log('第二个事件被触发!');
});
我们使用addEventListener方法分别给该按钮注册了两个事件监听器。当按钮被点击时,第一个事件监听器会显示 “第一个事件被触发!” 的消息在控制台上。而当鼠标悬停在按钮上时,第二个事件监听器会显示 “第二个事件被触发!” 的消息在控制台上。
删除事件的方式同样也有两种:
eventTarget.onclick = null;
eventTarget.removeEventListener(type, listener[, useCapture]);
它接受三个参数:事件类型(type)、要移除的事件监听器函数(listener)和一个可选的布尔值(useCapture),指定事件是否在捕获阶段进行处理。
const button = document.getElementById('myButton');
function handleClick() {
console.log('Button clicked!');
}
button.addEventListener('click', handleClick);
// 等待一段时间后移除事件监听器
setTimeout(() => {
button.removeEventListener('click', handleClick);
}, 3000);
事件流描述的是从页面中接收事件的顺序,事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流。
比如我们给一个div 注册了点击事件:
DOM 事件流分为3个阶段:
我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。
注意:
eventTarget.onclick = function(event) {}
eventTarget.addEventListener('click', function(event) {})
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
这个 event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去。当我们注册事件时, event 对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)。
官方解释:event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。
简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法。
比如:
以下是一些常见的事件对象属性和方法:
event.type
:返回事件的类型。event.target
或event.srcElement
:返回触发事件的元素。event.clientX
和event.clientY
:返回鼠标事件发生时的 X 和 Y 坐标。event.keyCode
和event.key
:返回键盘事件中按下的键的键码或键值。event.preventDefault()
:阻止事件的默认行为。event.stopPropagation()
:停止事件在DOM树中的传播。通过访问事件对象,我们可以在事件发生时获取相关的信息,并在事件处理函数中进行相应的操作。
target 和 this 的区别:
事件冒泡本身的特性,会带来的坏处,也会带来的好处,所以我们有时候需要阻止冒泡。
e.stopPropagation()
我们通过 stopPropagation() 方法即可阻止冒泡
以下是一个示例,展示如何使用e.stopPropagation()
阻止冒泡:
const parentElement = document.getElementById('parent');
const childElement = document.getElementById('child');
// 子元素点击事件处理程序
childElement.addEventListener('click', (e) => {
e.stopPropagation();
console.log('点击了子元素');
});
// 父元素点击事件处理程序
parentElement.addEventListener('click', () => {
console.log('点击了父元素');
});
// 输出:
// 点击了子元素
在上面的示例中,当点击子元素时,子元素的点击事件处理程序执行,并通过e.stopPropagation()
阻止了事件冒泡到父元素,所以父元素的点击事件处理程序不会被触发。
请注意,e.stopPropagation()
只会阻止事件在当前元素的后代元素中继续冒泡,而不会阻止事件在当前元素之外的其他元素上的冒泡。
事件委托也称为事件代理, 在 jQuery 里面称为事件委派。
事件冒泡本身的特性,会带来的坏处,也会带来的好处,下面我们来讲讲他的好处。
下面通过一个例子讲解:
<ul>
<li>知否知否,应该有弹框在手</li>
<li>知否知否,应该有弹框在手</li>
<li>知否知否,应该有弹框在手</li>
<li>知否知否,应该有弹框在手</li>
<li>知否知否,应该有弹框在手</li>
</ul>
我们需要点击每个 li 都会弹出对话框,以前需要给每个 li 注册事件,是非常辛苦的,而且访问 DOM 的次数越多,这就会延长整个页面的交互就绪时间。
事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
在上述例子中,我们可以给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上,ul 有注册事件,就会触发事件监听器,并且我们只操作了一次 DOM ,提高了程序的性能。
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
鼠标事件对象MouseEvent 的常用方法:
事件除了使用鼠标触发,还可以使用键盘触发, 注意给文档 document 添加键盘事件
注意:
键盘事件对象 KeyboardEvent 的常用方法:
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window,BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的一部分。
对于 DOM :
对于 BOM :
BOM 比 DOM 更大,它包含 DOM。
注意: window 对象是浏览器的顶级对象,定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。在调用的时候可以省略 window,前面学习的对话框都属于 window 对象方法,如 alert()、prompt() 等。
window.onload = function(){}
或者
window.addEventListener("load",function(){});
window.onload 是窗口 (页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等), 就调用的处理函数。
document.addEventListener('DOMContentLoaded',function(){})
DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。
如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适。
window.onresize = function(){}
window.addEventListener("resize",function(){});
window.onresize 是调整窗口大小加载事件, 当触发时就调用的处理函数。
注意:
window 对象给我们提供了 2 个非常好用的方法-定时器。
window.setTimeout(调用函数, [延迟的毫秒数]);
setTimeout() 方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。
举个例子:
function sayHello() {
console.log('Hello, world!');
}
window.setTimeout(sayHello, 2000);
通过定时器,sayHello
函数将在2秒后被调用,我们会延迟两秒在控制台输出“Hello, world!”。
注意:
setTimeout() 这个调用函数我们也称为回调函数 callback,普通函数是按照代码顺序直接调用,而这个函数,需要等待时间,时间到了才去调用这个函数,因此称为回调函数。
简单理解: 回调,就是回头调用的意思。上一件事干完,再回头再调用这个函数。
以前我们讲的 element.onclick = function(){} 或者 element.addEventListener(“click”, fn); 里面的 函数也是回调函数。
window.clearTimeout(timeoutID)
clearTimeout()方法取消了先前通过调用 setTimeout() 建立的定时器。
举个例子:
const delayedFunction = () => {
console.log('Delayed function called!');
};
// 创建定时器,延迟 2 秒后调用 delayedFunction
const timeoutID = window.setTimeout(delayedFunction, 2000);
// 取消定时器
window.clearTimeout(timeoutID);
在上面的代码中,首先我们使用window.setTimeout()
方法创建了一个定时器,将delayedFunction
作为回调函数,并指定了延迟时间为 2000 毫秒(即 2 秒)。window.setTimeout()
返回一个定时器的 ID,我们将其保存在timeoutID
变量中。
最后,通过调用window.clearTimeout(timeoutID)
方法,我们取消了之前创建的定时器,这样,定时器将不再触发,并且delayedFunction
不会被调用。
注意:
window.setInterval(回调函数, [间隔的毫秒数]);
setInterval() 方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。
举个例子:
function 每秒执行的函数() {
console.log("每秒执行一次");
}
// 用 setInterval() 调用每秒执行的函数,间隔为 1000 毫秒(即 1 秒)
window.setInterval(每秒执行的函数, 1000);
我们定义了一个函数 每秒执行的函数()
,它在控制台中打印一条消息。然后,我使用 window.setInterval()
方法每隔 1000 毫秒(1 秒)调用此函数。
注意:
window.clearInterval(intervalID);
clearInterval()方法取消了先前通过调用 setInterval()建立的定时器。
注意:
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象
function greet() {
console.log(this); // 在浏览器环境中输出:Window对象
}
greet();
const person = {
name: 'John',
greet: function() {
console.log(this.name); // 在greet方法中的this指向person对象,输出:John
}
};
person.greet();
function Person(name) {
this.name = name;
}
const john = new Person('John');
console.log(john.name); // 输出:John
首先JS 是单线程,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是: 如果JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
以下代码执行的结果是什么?为什么?
console.log(1);
setTimeout(function () {
console.log(3);
}, 1000);
console.log(2);
这段代码的输出结果是:
1
2
3
这是因为setTimeout函数是一个异步函数,它会在一定时间后将回调函数添加到任务队列中,而不会阻塞后续代码的执行。因此,代码会按照顺序执行console.log(1),然后执行setTimeout函数,将回调函数添加到任务队列中。然后立即执行console.log(2)。最后,当定时器计时结束后(即过了1000毫秒),事件循环会将回调函数放到调用栈中执行,所以会输出console.log(3)。
同步:
异步:
同步任务:
异步任务:
异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。
由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop)。
window 对象给我们提供了一个 location 属性用于获取或设置窗体的 URL,并且可以用于解析 URL 。 因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
URL即统一资源定位符 (Uniform Resource Locator, URL) 是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL 的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
http://www.itcast.cn/index.html?name=andy&age=18#link
navigator对象是JavaScript中的一个内置对象,提供了与浏览器相关的信息。它包含了有关浏览器和设备的信息,可用于检测浏览器的功能和特性,并根据不同的浏览器环境进行相应的操作。
下面是一些常用的属性和方法:
console.log(navigator.userAgent);
appName:返回浏览器的名称。常见的值有 “Netscape”、“Microsoft Internet Explorer”、“Chrome”、“Firefox” 等。
appVersion:返回浏览器的版本号。
platform:返回浏览器运行的平台,如 “Win32”、“Win64”、“MacIntel” 等。
language:返回浏览器的首选语言,通常是由操作系统或者浏览器设置的。
cookiesEnabled:返回一个布尔值,表示浏览器是否启用了Cookie。
geolocation:一个Geolocation对象,用于获取用户的地理位置信息。
userAgentData:一个UserAgentData对象,提供有关浏览器的更详细信息,如品牌、版本号、移动设备类型等。
registerProtocolHandler():向浏览器注册自定义的协议处理程序。
javaEnabled():返回一个布尔值,表示浏览器是否启用了Java。
window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互。该对象包含
用户(在浏览器窗口中)访问过的 URL。
offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
offset 系列常用属性:
offset:
style:
client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等。
scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。
如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发 onscroll 事件。
当鼠标移动到元素上时就会触发 mouseenter 事件类似 mouseover,它们两者之间的差别是
mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。
mouseenter 只会经过自身盒子触发
之所以这样,就是因为 mouseenter 不会冒泡
跟mouseenter搭配 鼠标离开 mouseleave 同样不会冒泡
核心原理:通过定时器 setInterval() 不断移动盒子位置。
实现步骤:
注意函数需要传递2个参数,动画对象和移动到的距离。
缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来
思路:
当我们需要让动画函数多个目标值之间移动时,我们需要判断步长是正值还是负值
随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案。
本地存储的特性:
存储数据:
sessionStorage.setItem(key, value)
获取数据:
sessionStorage.getItem(key)
删除数据:
sessionStorage.removeItem(key)
删除所有数据:
sessionStorage.clear()
存储数据:
localStorage.setItem(key, value)
获取数据:
localStorage.getItem(key)
删除数据:
localStorage.removeItem(key)
删除所有数据:
localStorage.clear()