当前位置: 首页 > news >正文

JavaScript学习第十章-第三部分(dom)

JavaScript学习第十章-第三部分(dom)

  • 事件对象
  • 冒泡行为
  • 事件委派
  • 事件捕获
  • bom对象
  • 事件循环

1、event事件

  • 事件对象

    • 事件对象是有浏览器在事件触发时所创建的对象,这个对象中封装了事件相关的各种信息

    • 通过事件对象可以获取到事件的详细信息

      • 比如:鼠标的坐标、键盘的按键…
    • 浏览器在创建事件对象后,会将事件对象作为响应函数的参数传递,

      ​ 所以我们可以在事件的回调函数中定义一个形参来接收事件对象

使用示例

当鼠标滑过的时候,将鼠标当前的坐标实时的显示出来

在这里插入图片描述

代码

<style>#box1 {width: 300px;height: 300px;border: 10px green solid;text-align: center;line-height: 300px;}</style>
</head>
<body><div id="box1"></div><script>/*event 事件- 事件对象- 事件对象是有浏览器在事件触发时所创建的对象,- 通过事件对象可以获取到事件的详细信息比如:鼠标的坐标、键盘的按键..- 浏览器在创建事件对象后,会将事件对象作为响应函数的参数传递,所以我们可以在事件的回调函数中定义一个形参来接收事件对象*/const box1 = document.getElementById("box1");// box1.onmousemove = event => {//     console.log(event)// }box1.addEventListener("mousemove",event => {console.log(event.clientX,event.clientY);//将当前鼠标的位置信息展示到box1中box1.textContent = '横坐标:'+event.clientX + ",纵坐标:"+event.clientY;})</script>
</body>

2、事件对象行为

在DOM中存在着多种不同类型的事件对象

  • 多种事件对象有一个共同的祖先 Event
    • event.target 触发事件的对象
    • event.currentTarget 绑定事件的对象(同this)
    • event.stopPropagation() 停止事件的传导
    • event.preventDefault() 取消默认行为
  • 事件的冒泡(bubble)
    • 事件的冒泡就是指事件的向上传到
    • 当元素上的某个事件被触发后,其祖先元素上的相同事件也会同时被触发
    • 冒泡的存在大大的简化了代码的编写,但是在一些场景下我们并不希望冒泡存在
      • 不希望事件冒泡时,可以通过事件对象来取消冒泡

取消超链接的默认行为

当页面上面有一个a标签,当我们点击的时候会触发它的默认事件跳转,这个时候我们想取消有两种方式;

"chao" href="https://lilichao.com">超链接</a>
方式1

方式1,缺点是不够灵活,如果用户是通过addEventListener方式,那么我们就监听不到了

const chao = document.getElementById("chao");chao.onclick = function() {return false;
}
方式2

preventDefault() 取消默认事件

chao.addEventListener("click",function(event) {// 取消默认行为event.preventDefault();})

event 对象

多种事件对象有一个共同的祖先 Event

使用示例
<div id="box1"></div>const box1 = document.getElementById("box1");box1.addEventListener("click",function(event) {/*在事件的响应函数中:event.target 表示的是触发事件的对象this 绑定事件的对象*/console.log("target",event.target);//<div id="box3"></div >console.log("this",this);// box1// currentTargetconsole.log("currentTarget:",event.currentTarget);// box1alert("我是box1")
})

在这里插入图片描述

冒泡事件

我们在div里面放了三个元素,box1 里面有 box2,box2里面有box3,那么他们的关系就是

box3 -> box2 -> box1 box1是他们的 共同祖先

演示冒泡顺序
<div id="box1">box1<div id="box2">box2<div id="box3">box3</div></div></div>// 冒泡演示,当我们点击box3的时候,我们看到  box3 -> box2 -> box1 都弹出来了
box2.addEventListener("click", function (event) {alert("我是box2")
})

在这里插入图片描述

阻止冒泡

  // 阻止冒泡,我们在 box3上面加了阻止冒泡事件后,当我们点击box3的时候,只有box3的提示弹出来了 // box2 继续回冒泡box3.addEventListener("click", function (event) {//阻止向上冒泡event.stopPropagation();alert("我是box3")})

3、冒泡应用

  • 当我们在讨论,冒泡是好还是坏的时候,实际上冒泡是对我们有利的;

  • 如果没有冒泡,那么我们写的一个事件,需要考虑他在页面任何元素都需要处理,

  • 类似于我们函数绑定事件一样,新加一个元素,我们就需要绑定一次的动作

小案例

写一个圆球,跟随鼠标移动

方式1

我们不采用冒泡的方式,直接绑定到指定的元素上面,看小球启动的效果

  <style>#box1 {width: 100px;height: 100px;border-radius: 50%;background-color: aqua;text-align: center;line-height: 100px;position: absolute;}#box2 {width: 500px;height: 500px;background-color: orange;}#box3{width: 200px;height: 200px;background-color: tomato;}#box4{width: 100px;height: 100px;background-color: skyblue;position: absolute;bottom: 0;}</style>
</head>
<body><div id="box1">圆球</div><div id="box2"></div><div id="box3" onclick="alert('box3')"><div id="box4" onclick="alert('box4')"></div></div></body>  
代码实现

当我们绑定box的时候,小球的移动会有迟钝,并且只能向一个方向,这个没有冒泡

  //当我们绑定box的时候,小球的移动会有迟钝,并且只能向一个方向box1.addEventListener("mousemove",(event) => {//console.log(event.x)box1.style.left = event.x + "px"box1.style.top = event.y + "px"})
方式2
      //如果我们直接绑定到document上面,因为冒泡的原因,最终会作用到document上document.addEventListener("mousemove", (event) => {//console.log(event.x)box1.style.left = event.x + "px"box1.style.top = event.y + "px"})

在这里插入图片描述

冒泡的好处演示

如果没有冒泡的存在,当小球移动到box2上面,那么就进不去了,我们来设置box2阻止冒泡

document.getElementById(“box2”).addEventListener(“mousemove”,event => {

​ //event.stopPropagation();

})

冒泡是否跟位置有关

  • 事件的冒泡和元素的样式无关,只和结构相关

  • box4是 box3的子元素,我们让box4发生相对定位,

  • 位置看起来是跟box3无关,但是我们点击box4的时候,一样会冒泡到box3上

案例演示

在这里插入图片描述

4、事件的委派

  • 只绑定一次事件,既可以让所有的超链接,包括当前的和未来新建的超链接都具有这些事件
  • 可以将事件统一绑定给document,这样点击超链接时由于事件的冒泡,
    • 会导致document上的点击事件被触发,这样只绑定一次,所有的超链接都会具有这些事件
使用示例
<body><button id="btn">增加超链接</button><hr /><ul id="list"><li><a href="javascript:;">链接一</a></li><li><a href="javascript:;">链接二</a></li><li><a href="javascript:;">链接三</a></li><li><a href="javascript:;">链接四</a></li></ul><script>/*我一个希望:只绑定一次事件,既可以让所有的超链接,包括当前的和未来新建的超链接都具有这些事件思路:可以将事件统一绑定给document,这样点击超链接时由于事件的冒泡,会导致document上的点击事件被触发,这样只绑定一次,所有的超链接都会具有这些事件*/const links = document.querySelector("ul a");const btn = document.getElementById("btn");const list = document.getElementById("list");//我们直接给绑定点击事件的时候直接绑定到最上级元素,document上 // 我们发现这种绑定会作用到任意的元素上面,这个时候需要精细的过滤了document.addEventListener("click",event => {alert(event.target.textContent)})btn.addEventListener("click",event => {list.insertAdjacentHTML("beforeend",'<li><a href="javascript:;">我是一个新的超链接</a></li>')})</script>
</body>
事件的委派-过滤

委派就是将本该绑定给多个元素的事件,统一绑定给document,这样可以降低代码复杂度方便维护,但是上面我们发现,无论我们点击哪个地方,都会触发该事件,那么我们需要根据条件过滤一次;

代码
<body><button id="btn">增加超链接</button><hr /><ul id="list"><li><a href="javascript:;">链接一</a></li><li><a href="javascript:;">链接二</a></li><li><a href="javascript:;">链接三</a></li><li><a href="javascript:;">链接四</a></li></ul><script>/*我一个希望:只绑定一次事件,既可以让所有的超链接,包括当前的和未来新建的超链接都具有这些事件思路:可以将事件统一绑定给document,这样点击超链接时由于事件的冒泡,会导致document上的点击事件被触发,这样只绑定一次,所有的超链接都会具有这些事件委派就是将本该绑定给多个元素的事件,统一绑定给document,这样可以降低代码复杂度方便维护*/const btn = document.getElementById("btn");const list = document.getElementById("list");// 获取list中所有的超链接const links = list.getElementsByTagName("a");console.log("links", Array.from(links))//我们直接给绑定点击事件的时候直接绑定到最上级元素,document上 // 我们发现这种绑定会作用到任意的元素上面,这个时候需要精细的过滤了document.addEventListener("click",event => {//在代码执行之前判断一下事件是由谁复发// 检查 event.target 是否在links 中存在//console.log(event.target)if([...links].includes(event.target)) {alert(event.target.textContent)}})btn.addEventListener("click",event => {list.insertAdjacentHTML("beforeend",'<li><a href="javascript:;">我是一个新的超链接</a></li>')})</script>
</body>
</html>

在这里插入图片描述

5、事件的捕获

事件的传播机制:

  • 在DOM中,事件的传播可以分为三个阶段
    • 捕获阶段 (由祖先元素向目标元素进行事件的捕获)(默认情况下,事件不会在捕获阶段触发)
    • 目标阶段 (触发事件的对象)
    • 冒泡阶段 (由目标元素向祖先元素进行事件的冒泡)
  • 事件的捕获,指事件从外向内的传导,当前元素触发事件以后,会先从当前元素最大的祖先元素开始向当前元素进行事件的捕获
  • 如果希望在捕获阶段触发事件,可以将addEventListener的第三个参数设置为true
    • 一般情况下我们不希望事件在捕获阶段触发,所有通常都不需要设置第三个参数

公共代码

<style>#box1 {width: 300px;height: 300px;background-color: greenyellow;}#box2 {width: 200px;height: 200px;background-color: orange;}#box3 {width: 100px;height: 100px;background-color: tomato;}</style>
</head>
<body><div id="box1"><div id="box2"><div id="box3"></div></div></div>const box1 = document.getElementById("box1");const box2 = document.getElementById("box2");const box3 = document.getElementById("box3");

冒泡阶段 从内向外

 box1.addEventListener("click",event => {alert('box1阶段===》' + event.eventPhase);// eventPhase 表示事件触发的阶段// //1 捕获阶段 2 目标阶段 3 冒泡阶段})box2.addEventListener("click", event => {alert('box2阶段===》' + event.eventPhase);// eventPhase 表示事件触发的阶段// //1 捕获阶段 2 目标阶段 3 冒泡阶段})box3.addEventListener("click", event => {alert('box3阶段===》' + event.eventPhase);// eventPhase 表示事件触发的阶段// //1 捕获阶段 2 目标阶段 3 冒泡阶段})

捕获阶段 从外向内

// 当点击box3的时候,先触发 box1(1)  box2(1) box3(2)// 当点击box2的时候,先触发 box1(1)  box2(2) // 当点击box1的时候,先触发 box1(2)  box1.addEventListener("click", event => {alert('box1捕获阶段===》' + event.eventPhase);// eventPhase 表示事件触发的阶段// //1 捕获阶段 2 目标阶段 3 冒泡阶段},true)box2.addEventListener("click", event => {alert('box2捕获阶段===》' + event.eventPhase);// eventPhase 表示事件触发的阶段// //1 捕获阶段 2 目标阶段 3 冒泡阶段}, true)box3.addEventListener("click", event => {alert('box3捕获阶段===》' + event.eventPhase);// eventPhase 表示事件触发的阶段// //1 捕获阶段 2 目标阶段 3 冒泡阶段}, true)

在这里插入图片描述

6、bom 对象

BOM (浏览器对象模型)是浏览器提供的一组API,通过JavaScript与浏览器窗口文档、历史记录等组件交互。核心对象是window,其他常用对象包括location(地址栏)、history(历史记录)、navigator(浏览器信息)等

BOM对象:

  • Window —— 代表浏览器窗口(全局对象)
  • Navigator —— 浏览器的对象(可以用来识别浏览器)
  • Location —— 浏览器的地址栏信息
  • History —— 浏览器的历史记录(控制浏览器前进后退)
  • Screen —— 屏幕的信息

BOM对象都是作为window对象的属性保存的,所以可以直接在JS中访问这些对象

console.log(“window”,window);

console.log(“Navigator”, Navigator);

console.log(“Location”, Location);

6.1 Navigator对象

Navigator —— 浏览器的对象(可以用来识别浏览器)

​ userAgent 返回一个用来描述浏览器信息的字符串

​ 文档地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator#%E5%AE%9E%E4%BE%8B%E6%96%B9%E6%B3%95

使用示例

判断浏览器

<body><script>/*- Navigator —— 浏览器的对象(可以用来识别浏览器)userAgent 返回一个用来描述浏览器信息的字符串文档地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator#%E5%AE%9E%E4%BE%8B%E6%96%B9%E6%B3%95        */// 浏览器对象字符串console.log(navigator)console.log(navigator.userAgent);// 判断浏览器let sBrowserconst sUsrAg = navigator.userAgent// The order matters here, and this may report false positives for unlisted browsers.if (sUsrAg.indexOf("Firefox") > -1) {sBrowser = "Mozilla Firefox"// "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"} else if (sUsrAg.indexOf("SamsungBrowser") > -1) {sBrowser = "Samsung Internet"// "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G955F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Mobile Safari/537.36} else if (sUsrAg.indexOf("Opera") > -1 ||sUsrAg.indexOf("OPR") > -1) {sBrowser = "Opera"// "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.106"} else if (sUsrAg.indexOf("Trident") > -1) {sBrowser = "Microsoft Internet Explorer"// "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; Zoom 3.6.0; wbx 1.0.0; rv:11.0) like Gecko"} else if (sUsrAg.indexOf("Edge") > -1) {sBrowser = "Microsoft Edge (Legacy)"// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299"} else if (sUsrAg.indexOf("Edg") > -1) {sBrowser = "Microsoft Edge (Chromium)"// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.64} else if (sUsrAg.indexOf("Chrome") > -1) {sBrowser = "Google Chrome or Chromium"// "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/66.0.3359.181 Chrome/66.0.3359.181 Safari/537.36"} else if (sUsrAg.indexOf("Safari") > -1) {sBrowser = "Apple Safari"// "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1 980x1306"} else {sBrowser = "unknown"}alert(`You are using: ${sBrowser}`)</script>
</body>

在这里插入图片描述

6.2 location 对象

location 表示的是浏览器地址栏的信息

  • 可以直接将location的值修改为一个新的地址,这样会使得网页发生跳转
  • location.assign() 跳转到一个新的地址
  • location.replace() 跳转到一个新的地址(无法通过回退按钮回退)
  • location.reload() 刷新页面,可以传递一个true来强制清缓存刷新
  • location.href 获取当前地址
使用示例

console.log(location.href)

location = “https://www.lilichao.com”

location.assign(“https://www.lilichao.com”)

location.replace(“https://www.lilichao.com”)

location.reload(true)

6.3 history 对象

  • history.back() 回退按钮
  • history.forward() 前进按钮
  • history.go() 可以向前跳转也可以向后跳转
使用示例
 console.log(history.length)//history.back()//history.forward()// 正数代表是向前,负数是后退 x 步
//history.go(-1)

7、定时器

通过定时器,可以使代码在指定时间后执行

  • 设置定时器的方式有两种:
    • setTimeout()
      • - 参数:
        1. 回调函数(要执行的代码)
        2. 间隔的时间(毫秒)
      • 关闭定时器
        • clearTimeout()
    • setInterval() (每间隔一段时间代码就会执行一次)
      • 参数:
        1. 回调函数(要执行的代码)
        2. 间隔的时间(毫秒)
      • 关闭定时器
        • clearInterval()

setTimeout

// 间隔2s中后执行const timer = setTimeout(() => {console.log('我是定时器代码==》')},2000)// 关闭定时器clearTimeout(timer);

setInterval

<body><h1>0</h1><button>停止</button><script>/*通过定时器,可以使代码在指定时间后执行- 设置定时器的方式有两种:setTimeout()- 参数:1. 回调函数(要执行的代码)2. 间隔的时间(毫秒)- 关闭定时器clearTimeout()setInterval() (每间隔一段时间代码就会执行一次)- 参数:1. 回调函数(要执行的代码)2. 间隔的时间(毫秒)- 关闭定时器clearInterval()*/// 间隔2s中后执行const timer = setTimeout(() => {console.log('我是定时器代码==》')},2000)// 关闭定时器clearTimeout(timer);const h1html = document.querySelector("h1");let num = 0;//间隔固定的时间一直执行const interTime = setInterval(() => {num ++;h1html.textContent = num;}, 50);//手动停止const btn = document.getElementsByTagName("button")[0]btn.onclick = function() {clearInterval(interTime);}</script>
</body>

在这里插入图片描述

8、事件循环

事件循环(event loop)

  • 函数在每次执行时,都会产生一个执行环境
    时产生的一切数据
    • 问题:函数的执行环境要存储到哪里呢?
    • 函数的执行环境存储到了一个叫做调用栈的地方
    • 栈,是一种数据结构,特点 后进先出

​ 调用栈(call stack)

  • 调用栈负责存储函数的执行环境
    境会作为一个栈帧
    插入到调用栈的栈顶,函数执行完毕其栈帧会自动从栈中弹出

使用示例

     function fn() {let a = 10;let b = 20;function fn2() {console.log("fn2")}fn2();console.log("fn~~")}fn();console.log("1111")</script>

在这里插入图片描述

在这里插入图片描述

9、事件循环-消息队列

事件循环(event loop)

  • 函数在每次执行时,都会产生一个执行环境
    数执行时产生的一切数据
    • 问题:函数的执行环境要存储到哪里呢?
    • 函数的执行环境存储到了一个叫做调用栈的地方
    • 栈,是一种数据结构,特点 后进先出
    • 队列,是一种数据结构,特点 先进先出

​ 调用栈(call stack)

  • 调用栈负责存储函数的执行环境
    执行环境会作为一个栈帧
    插入到调用栈的栈顶,函数执行完毕其栈帧会自动从栈中弹出

​ 消息队列

  • 消息队列负责存储将要执行的函数
    响应函数并不是直接就添加到调用栈中的
    因为调用栈中有可能会存在一些还没有执行完的代码
    • 事件触发后,JS引擎是将事件响应函数插入到消息队列中排队

代码演示

  function fn() {let a = 10let b = 20function fn2() {console.log("fn2")}fn2()console.log("fn~")}fn()console.log(1111);// 我们思考,当我们有一个函数没有调用的时候,那么他是应该放到哪里呢// 当我们执行这个函数的时候,是否立即就执行呢// const btn1 = document.getElementById("btn1");const btn2 = document.getElementById("btn2");// 执行此函数,会有一个3s的时间等待操作btn1.onclick = function() {alert("btn1事件被触发了!!!");const begin = Date.now();const num = document.getElementById("num");while(Date.now() - begin < 3000) {// let temNum = num.textContent;// let timer;// if(temNum <= 0) {//    clearTimeout(timer);//    break;// }// num.textContent = temNum - 100}}btn2.onclick = function() {alert("我是btn2的操作")}</script>

在这里插入图片描述

在这里插入图片描述

10、定时器-消息队列

定时器的本质,就是在指定的时间后将函数添加到消息队列中

示例1

  /***   定时器的本质,就是在指定的时间后将函数添加到消息队列中*/console.time()setTimeout(() => {console.timeEnd();console.log("定时器执行了!!!")}, 3000);const begion = Date.now();while(Date.now() - begion < 6000) {}

在这里插入图片描述

setInterval()

setInterval() 每间隔一段时间就将函数添加到消息队列中,但是如果,函数执行较慢,那么就无法确保每次执行的间隔是一样的

    console.time('定时间隔执行');setInterval(() => {console.timeEnd("定时间隔执行");// 如果我自己的逻辑执行需要1s 那么,实际上下次就是执行时间 + 间隔的时间//console.log("定时器执行了~~~~")alert("执行!!!")console.time("定时间隔执行")}, 3000);

在这里插入图片描述

创建一个确保函数每次执行都有相同的间隔

console.time("固定间隔")setTimeout(function fn(){console.timeEnd("固定间隔");//console.log("我开始执行了 !")alert("---")// 在settimeout的回调函数的最后,再调用一次setTimeout函数console.time("固定间隔")setTimeout(fn,3000);}, 3000);

在这里插入图片描述

函数执行顺序

 // 函数执行顺序setTimeout(() => {console.log('0毫秒以后开始执行~~~')}, 0);//先执行,因为他是全局作用域,先进栈,setTimeout需要先进队列,所以慢一些console.log(22222)
http://www.dtcms.com/a/334537.html

相关文章:

  • B3865 [GESP202309 二级] 小杨的 X 字矩阵(举一反三)
  • C#计算阶乘程序改进
  • C# 元组的用法
  • Nona生命之树作品TRO突袭,冻结名单曝光
  • Vue2.x核心技术与实战(一)
  • 摩搭api 实现
  • 025 理解文件系统
  • 多机编队——(6)解决机器人跟踪过程中mpc控制转圈问题
  • 第四章 Linux实用操作
  • OpenJDK 17的C1和C2编译器实现中,方法返回前插入安全点(Safepoint Poll)的机制
  • 【LeetCode题解】LeetCode 35. 搜索插入位置
  • [Linux] Linux逻辑卷管理
  • 知识点汇总linuxC高级 -2系统命令压缩与链接
  • RK3568 NPU RKNN(三):RKNN-ToolKit2模型构建与推理
  • 【LeetCode】算法详解#13 ---回文链表
  • Vue 3.5重磅更新:响应式Props解构,让组件开发更简洁高效
  • [Linux] Linux交换空间管理 Linux系统启动原理
  • 慧穗云开放平台 CDK 开票对接
  • echart中x的0位置出现柱子宽度被裁掉一部分的问题
  • 技术日记2025年08月16日
  • 基于FPGA的实时图像处理系统(1)——SDRAM回环测试
  • python---异常处理
  • Redis知识整理
  • 【论文笔记】STORYWRITER: A Multi-Agent Framework for Long Story Generation
  • 云服务平台主流架构的相关知识体系剖析
  • ABM和强化学习-2015年全国大学生数学建模竞赛B题
  • 安卓11 12系统修改定制化_____修改系统 解锁system分区 去除data加密 自由删减系统应用
  • JetPack系列教程(七):Palette——让你的APP色彩“飞”起来!
  • sql链接的url中serverTimezone的作用
  • 【大模型微调系列-04】 神经网络基础与小项目实战