五、BOM
1.BOM概述
①什么是BOM?
BOM(Borwer Object Model)即浏览器对象模型
- BOM比DOM更大,它包含DOM
②BOM有什么用?
它提供了独立于内容而与浏览器窗口进行交互的对象
-
如:后退页面,刷新页面,滚动页面
-
核心对象是window
③BOM由什么组成?
BOM由一系列相关的对象构成,并且每个对象都提供了很多方法和属性。
④BOM缺乏标准
- 说明兼容性差
JavaScript的标准化组织是ECMA
DOM的标准化组织是W3C
BOM最初是Netscape浏览器标准的一部分,但不同的厂商在各自浏览器中各自定义的
⑤DOM和BOM的对比
DOM是文档对象模型--》页面操作
BOM是浏览器对象模型--》浏览器交互操作
2.window对象
2.1window概念
window对象是浏览器的顶级对象,里面包含系统定义好的属性+方法
1️⃣它是js访问浏览器窗口的一个接口
2️⃣它是一个全局对象。
- 定义在全局作用域中的变量、函数都会自动变成window对象的属性和方法。
- 即window.num和num/window.fn()和fn()是一样的
3️⃣调用时可以省略window
- 如:window.alert()-->alert()
4️⃣window下的特殊属性window.name,所以定义变量名不用name
2.2窗口加载事件
原先的js代码不能放在获取的元素之前。如:实现点击按钮弹出弹框。
其中js代码是在button元素的下方:
<button>点击</button> <script> var btn = document.querySelector('button'); btn.onclick = function(){ alert("成功点击!!"); } </script>
而如果将js代码写在button上方,则无作用:
<button>点击</button> <script> var btn = document.querySelector('button'); btn.onclick = function(){ alert("成功点击!!"); } </script>
解决此问题就可以使用window.onload窗口加载事件。
(1)window.onload
window.onload是窗口(页面)加载事件,当文档内容完全加载完成再触发该事件(包括图像、脚本文件、css文件等),调用其处理函数。
- window.onload是等待页面元素全加载完,再去执行处理函数的
- 有了window.onload可将js写到页面元素上方
①传统写法:
- 传统写法的window.onload注册事件的方式只能写一次,如果有多个,以最后一个window.onload为准。
window.onload = function(){ //将要执行的js代码放入 //解决之前元素找不到的问题 }
②方法监听注册方式[推荐]
-
方法监听注册方式可注册多次
-
采用addEventListener()方法 [ 不加on ]
window.addEventListener('load',function(){ //要执行的js代码 })
(2)DOMContentLoaded
DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表、图片、flash等【ie9以上才支持】
- 当图片很多时,采用onload触发所需的时间很长,影响用户与页面的交互体验,而DOMContentLoaded则无需加载图片,顶多图片处于加载,但页面交互都能正常使用。
document.addEventListener('DOMContentLoaded',function(){ //js代码放里面 })
(3)区分
①load是等页面内容全部加载完毕,包含页面dom元素、图片、flash、css等
- 更慢
②DOMContentLoaded是DOM加载完毕,不包含图片、flash、css等
- 更快
2.3调整窗口大小事件
(1)resize事件
window.onresize是调整窗口大小加载事件,当触发时就调用的处理函数
- 窗口大小发生像素变化,就会触发该事件
- 使用场景:完成响应式布局
- window.innerWidth可获得当前屏幕宽度
①传统写法:
window.onresize = function(){ }
②方法监听注册方式:
window.addEventListener('resize',function(){ });
3.定时器
window对象给我们提供了两种定时器
3.1开启定时器 setTimeout()
setTimeout()方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。
1️⃣有参数
-
调用函数 :多少秒后执行的函数
-
可直接写函数/函数名
//①此时回调函数 为匿名函数 window.setTimeout(function(){},[延迟的毫秒数]); //②直接写函数名的形式 window.setTimeout(fn1(),[延迟的毫秒数]); //③字符串函数名的形式 window.setTimeout('fn1()',[延迟的毫秒数])
-
-
延迟毫秒数:可选参数,不写默认为0
window.setTimeout(调用函数,[延迟的毫秒数]);
表示:到了多少毫秒数后,就调用函数
2️⃣注意
-
①window在调用时可以省略
-
②延迟时间单位是毫秒,可省略,默认为0
-
③调用函数可写函数/函数名/‘函数名()’
-
④多个定时器,常给定时器起名+标识符
var time1= setTimeout(callback,3000);
var time 2 = setTimeout(callback,500
3️⃣回调函数callback
setTimeout(fn,[延迟毫秒数])其中调用fn称为回调函数
-
普通函数:是按照代码顺序直接调用
-
回调函数:需要等待时间,时间到了后再去调用这个函数
回调函数即上一件事干完,再回头调用这个函数
element.onclick =function(){}和element.addEventListener('click',fn)里面的函数也是回调函数。
3.2停止 cleatTimeout(定时器ID)
window.clearTimeout(timeout ID)方法取消了先前通过调用 setTimeout() 建立的定时器。
- window可省略
1️⃣有参数
- timeout ID:取消的定时器ID
- 注意设置定时器时要设置标识符(赋给一个变量)
window.clearTimeout(定时器ID);
<button>点击停止定时器</button> <script> //设置定时器 var timer = setTimeout(function(){ console.log('爆炸了'); },5000) //添加监听事件,点击按钮执行... btn.addEventListener('click',function(){ //清除timer这个定时器 clearTimeout(timer); }) </script>
2️⃣注意
①window.clearTimeout( )中window可省略
②参数为取消定时器的标识符名
-
要注意设置定时器时,要声明一个变量,将定时器赋给它
var time1 = setTimeout(function(){},[延迟时间毫秒数]
【案例】5秒后自动关闭的广告
<style> div{ width: 100px; height: 100px; background-color: antiquewhite; } </style> <div>广告位</div> <script> var div = document.querySelector('div'); //等待页面内容加载完成 window.addEventListener('load',function(){ //设置定时器setTimeout()方法,window可省略 window.setTimeout(function (){ div.style.display = 'none'; },5000) }); </script>
3.3重复调用 setInterval()
window.setInterval()方法重复调用一个函数,每隔这个时间,就会调用一次回调函数。
- 即每隔多久,调用一次该函数
1️⃣有参数
- 回调函数:调用的函数
- 间隔的毫秒数:多少时间,再调用函数
window.setInterval(回调函数,[间隔的毫秒数]);
2️⃣注意:
①window可省略
②调用函数可直接写**函数、函数名、**字符串‘函数名’三种
③间隔毫秒数省略默认为0,单位:毫秒;表示多少毫秒就自动调用该函数
④有多个定时器,建议给定时器赋个标识符
3️⃣示例
//每隔1秒就调用一次回调函数 setInterval(function(){ console.log('调用啦!'); },1000);
4️⃣setTimeout和setInterval
setTimeout是到了延迟时间就调用一次回调函数
- 只执行一次
setInterval是每次到了延迟时间都调用一次回调函数
- 一直重复执行
3.4停止重复调用
window.clearInterval(定时器名)可用于清除定时器效果。
- 但注意定时器名要定义在全局变量,这样函数事件才可以访问
- 定时器名要赋null值
clearInterval(定时器名); //清除定时器时,要注意定时器一定有名字 //定时器名字不能定义在事件函数中 //定时器名字要定义在全局中,初值为null
要停止定时器时需指定定时器,因而开启定时器时要给定时器起名,注意要定义为全局变量,同时赋null值。
【案例】停止定时器
<button class="begin">开启定时器</button> <button class="stop">关闭定时器</button> <script> var b = document.querySelector('.begin'); var s = document.querySelector('.stop'); var timer = null; b.addEventListener('click',function(){ timer = setInterval(function(){ console.log("哈哈哈哈"); },1000) }) s.addEventListener('click',function(){ clearInterval(timer); }) </script>
【案例】秒杀倒计时
-
分析:
倒计时是不断变化,采用定时器(setInterval)
三个黑盒子存放时分秒
三个黑盒子利用innerHTML放入对应时、分、秒
-
思路:
①获取元素,hour/minute/second
②计算倒计时的函数countDown
- 当前时间戳毫秒数-截止时间戳毫秒数(写在函数外,定义全局变量)
- 毫秒换算成秒
- 相差hour: /60/60%24
- 相差minute:/60%60
- 相差second:%60
- 三目运算符解决前+0
- innerHTML解决替换内容
③定义setInterval倒计时函数,设置每1秒调用coutDown函数。
④最后在获得当前时间后,补充调用一次coutDown避免刷时页面空白。
- js代码
<script> //1.获取元素,时分秒 var hour = document.querySelector('.hour'); var minute = document.querySelector('.minute'); var second = document.querySelector('.second'); //2.将定时器结束时间设置为全局变量,不在函数中修改 var inputTime = +new Date('2023-3-19 00:00:00'); //4.每个一秒调用setInterval自动定时器 window.setInterval(countDown,1000); //3.编写计算倒计时的函数 function countDown(){ //获得当前时间的总毫秒数 var nowTime = +new Date(); //求间隔时间 inputTime-nowTime 毫秒数--->除以1000 var times = (inputTime-nowTime) /1000; //①求小时 var h = parseInt(times/60/60%24); h = h < 10 ? '0'+ h : h; hour.innerHTML = h; //②求分钟 var m = parseInt(times/60%60); m = minute < 10 ? '0'+ m : m; minute.innerHTML = m; //③求秒 var s = parseInt(times%60); s = s < 10?'0'+s:s; second.innerHTML = s; } </script>
- html+css代码:
<style> .recommend_first { width: 192px; height: 263px; background-color: #cc9756; } .recommend_first a { float: left; width: 192px; height: 100%; background-color: #CC9756; color: #fff; } a { text-align: center; text-decoration: none; } .recom_ico { font-family: 'icomoon'; font-size: 66px; color: #fff; } .recom_title { font-size: 30px; font-weight: 600; margin-top: 31px; } .recom_time { width: 180px; margin: 10px 0 0 4px; } .time_num { float: left; width: 35px; height: 35px; background-color: #000; margin-left: 10px; display: block; color: #fff; line-height: 35px; font-size: 24px; } .time_point { float: left; margin-top: -2px; width: 10px; font-size: 28px; color: #fff; padding-left: 10px; line-height: 35px; } </style> <body> <div class="recommend_first fl"> <a href="#"> <div class="recom_title">臻品秒杀</div> <div><i class="recom_ico"></i></div> <!--此处用的是字体图标,自己去网上找然后配置即可 ,如果直接粘贴在自己的电脑上会显示不出来--> <h4>距离结束本场结束还有</h4> <div class="recom_time"> <div class="time_num hour">01</div> <span class="time_point">:</span> <div class="time_num minute">20</div> <span class="time_point">:</span> <div class="time_num second">40</div> </div> </a> </div>
【案例】发送短信后禁用60秒按钮
- 效果:
按钮点击后会禁用disable=true
按钮里内容会发生变化,显示“还剩xxx秒”,利用定时器
定义一个变量。在定时器内,不断递减
变量为0,停止定时器,恢复按钮初始态
- 思路:
①定义倒计时变量i+定时器变量timer
②获取按钮元素
③绑定点击事件->禁用按钮+开启倒计时+给倒计时赋给timer
④每次倒计时,判断i是否等于0
等于0,清除倒计时+按钮启用+恢复按钮初始值+倒计时变量赋初始值
不等于0,innerHTML修改按钮内容+i--
- 代码如下:
<input type="number"><button>发送</button> <script> var btn = document.querySelector('button'); var i = 10; //(1)点击按钮,开始60秒倒计时 btn.addEventListener('click',function(){ btn.disabled = true; var timer = null; //定义定时器 timer = setInterval(function(){ //(2)若60秒倒计时结束 if(i == 0){ //①清除倒计时 clearInterval(timer); i=10; //②按钮启用 btn.disabled = false; btn.innerHTML = '发送'; }else{ btn.innerHTML = '还剩下'+i+'秒'; i--; } },1000) }) </script>
3.5this指向问题
this执向的永远是调用它的对象
在函数定义时难以判断,而函数执行时十分明确。
(1)全局作用域或普通函数中:
this指向全局对象window
- 定时器中的this指向window
①因为函数需要被调用才可以执行,而js中调用函数其实省略了window.函数()
②定时器也省略了window.setInterval(),因而this指向window
console.log(this);//指向window function fn(){ console.log(this);//指向window }
(2)对象方法中:
this指向方法的调用者
var o = { sayHi : function(){ console.log(this);//指向sayHi } }
(3)事件函数中:
this指向事件函数的调用者
<button><button> <script> var btn = document.querySelector('button'); btn.onclick = function(){ console.log(this);//this指向btn这个按钮对象 } </script>
(3)构造函数中:
this指向构造函数的实例对象
因为new会指向一个空间,创建一个新的对象,则this就指向这个对象,而实例化后会将对象赋给实例对象,所以this就指向实例对象
function Fun(){ console.log(this);//this指向fun } var fun = new Fun();
4.js执行机制
4.1js是单线程
js的一大特点是单线程,也就是同一时间只能做一件事。
因为js主要是用于处理页面中的交互,以及操作DOM而诞生,对DOM元素进行添加和删除,自然是先添加后删除。
(1)单线程:
所有的任务需要排队,前一个任务结束再执行后一个任务。
- 产生的问题:
js执行时间过长,导致页面渲染不连贯,出现页面渲染加载阻塞的感觉
eg:打印1后就需要等待10秒再打印3,和2,需要很久的等待时间(但如今已经改善啦,变成同步,先12后3)
(2)js同步和异步
提出了Web Worker标准,允许js脚本创建多个线程,于是出现了同步和异步。
①同步任务
前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的
- 同步任务都在主线程上执行,放在执行栈中
②异步任务
在做某件事的同时,再去做其他的事情
- 异步任务通常是回调函数。放在任务队列中
- 分为以下三种:
- 普通事件,如click/resize等
- 资源加载,如load、error等
- 定时器,如setInterval、setTimeout等
执行栈中先执行,任务队列后执行
4.2执行机制
1️⃣先执行执行栈中的同步任务
2️⃣遇到回调函数,交给异步进程处理
- 鼠标/键盘事件:执行了事件-->再放到任务队列中
- 定时器:时间到了--->再放到任务队列中执行
3️⃣一旦执行栈中全部同步任务执行完成,按次序读取任务队列的异步任务,被读取的异步任务结束等待状态,开始执行。
【执行栈会随时监控任务队列中是否有要执行的异步任务】
4.3事件循环
主线程执行栈不断的从任务队列中重复获得任务、执行任务再获取任务,再执行,该机制被称为事件循环(event loop)
5.location对象
window对象提供了location属性用于获取或设置窗体的URL,并可以用于解析URL。
- 该属性会返回一个对象,所以也称为location对象
5.1URL
统一资源定位符(Uniform Resource Locator,URL)是互联网上的标准资源地址。
互联网每个文件都有一个唯一的URL,它包含:文件的位置+浏览器该如何处理它。
protocol://host[:port]/path/[?query]#fragment
如:
http://www.itcast.cn/index.html?name=andy&age=18#link
5.2location对象的属性
location对象的属性有:
(1)location.href
location.href可用于跳转页面和得到页面URL
【案例】过5秒跳转页面
思路:innerHTML改变内容,setInerval设置定时器,location.href设置跳转网址
<div></div> <script> var div = document.querySelector('div'); var i = 5; setInterval(function(){ div.innerHTML = '过'+ i + '秒跳转页面'; i--; if(i == 0){ location.href="http://www.baidu.com"; } },1000) </script>
(2)location.search
location.search用于获取url中的参数,会获取?+xxx
- 常和substr+split一起使用
- sustr('起始位置',截取几个字符)
- split以xx字符分隔,获取到数组中
【案例】输入用户名点击登录,跳转到首页并显示用户名
- 思路:
①表单提交将参数从login页面->index页面
②利用location.search获取URL中的参数
③去掉?:substr('起始位置','截取几个字符');
④分隔=:split('以xx符号分隔'),形成数组
【注意:中文会出现乱码,在之后会讲解】
- login.html中代码:
<!-- 完成将参数传到index.html页面中 --> <form action="index.html"> 用户名:<input type="text" name="uname"><input type="submit" value="登陆"> </form>
- index.html中代码:
<h1>欢迎你,<span>xxx</span></h1> <script> var span = document.querySelector('span'); var arr = location.search.substr(1).split('=')//去掉问号再以=分隔 console.log(arr); span.innerHTML = arr[1]; </script>
5.3location对象的方法
(1)location.assign()
与href一样,可跳转页面,称为重定向页面
- 可记录浏览历史,实现后退功能
location.assign('网址');//可跳转网址,同可回退页面
(2)location.replace()
location.replace('网址');//可跳转网址,但不可回退页面
替换当前页面,不记录历史,所以不可后退页面
(3)location.reload()
location.reload()是用于重新加载页面的
-
不设置参数,则为重新加载页面=>刷新按钮或f5
-
若设置参数为true,则为强制刷新从服务器中去取数据=>ctrl+f5
6.navigator对象
navigator对象包含了有关浏览器的信息。
如:
- 浏览器端打开京东,显示京东的浏览器端页面
- PC端打开京东,显示京东的PC端页面
6.1userAgent
userAgent,用于返回由客户端发送服务端的user-agent头部的值。
头部信息中包含用户主机/利用什么终端打开页面等等信息
如:判断用户使用哪个终端打开的页面:
7.history对象
window的history对象是用于与浏览器历史记录进行交互,该对象包含用户,访问过的URL
7.1back()
相当于浏览器的后退功能
7.2forward()
相当于浏览器的前进功能
【back()和forward()功能都是用于有历史记录时,才能实现前进+后退】
7.3go(参数)
前进+后退功能。
- 参数1->前进
- 参数-1->后退1个页面