写在前面:本文仅包含BOM内容,JavaScript传送门在这里,DOM传送门在这里。
本文内容是假期中刷的黑马Pink老师视频(十分感谢Pink老师),原文保存在个人的GitLab中,如果需要写的网页内容信息等可以评论联系我,若是编辑博文中出现了忘记上传的图片或者错位的图片欢迎评论区指正。写作不易,欢迎点赞、收藏+关注。
文章目录
- BOM 导论
- 什么是BOM
- DOM 与 BOM 对比
- 一些描述
- 窗口加载事件
- 使用`window.onload`来改变`script`标签的位置
- 通过监听事件的方式写多个`load`
- 通过`DOMContentLoaded`事件来获取窗口加载事件
- 窗口大小变化事件
- 回调函数
- `setTimeout` 定时器
- 定时器函数的使用
- 通过匿名函数调用
- 通过函数名调用
- 通过函数名字符串调用 | 不推荐
- 区分不同的定时器
- 清除定时器
- `setInterval()` 定时器
- `setInterval()` 的使用
- 清除定时器 `setInterval()`
- this指向问题
- `location`对象
- `location`相关属性与方法
- `navigator`对象获取浏览器信息
- 历史记录
- `forward()` 前进 与 `back()` 后退
- 页面偏移量 offsetLeft 与 offsetTop
- `offsetLeft` 与 `offsetTop`
- `offsetWidth`与`offsetHeight`
- `offsetParent`
- `client` 系列
- `scroll`系列
- `scroll` 属性
- `scroll` 方法
- 移动端事件
- 触摸时间对象
- 本地存储
- sessionStorage
- localStorage
BOM 导论
什么是BOM
BOM(Browser Object Model)是浏览器对象模型,他提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是
window
。BOM 是由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
BOM缺乏标准,JavaScript语法的标准化组织室ECMA,DOM的标准化组织是W3C,BOM最初是Netscape(网景公司)浏览器标准的一部分。
DOM 与 BOM 对比
DOM | BOM |
---|---|
文档对象模型 | 浏览器对象模型 |
DOM就是把「文档」当做一个「对象」来看待 | 把「浏览器」当做是一个「对象」来看待 |
DOM的顶级对象是document | BOM的顶级对象是window |
DOM的主要学习是操作页面元素 | BOM学习的事浏览器窗口交互的一些对象 |
DOM是W3C标准 | BOM是浏览器厂商在各自浏览器上定义的,兼容性较差 |
BOM 与 DOM 的关系
一些描述
- 我们常用的
document.xxx
(如document.quertSelector()
,举例在下面的代码段) ,完整的写法是window.documnt.xxx
- 如果我们在script中定义了一个全局变量(以
num
举例,如下代码),那么我们真正的调用方式其实是window.num
window
包含一些方法,如我们常用的alert
,我们也可以在前面加上window.
使用,示例如下
<body><div>我是Jim.kk</div><script>// 1. 方法调用的省略写法document.querySelector('div');// 2. 方法调用的完整写法window.document.querySelector('div');var num = 10;// 3. 全局变量的省略写法console.log(num);// 4. 全局变量的完整写法console.log(window.num);// BOM的alert方法window.alert('我是Jim.kk');</script>
</body>
窗口加载事件
使用window.onload
来改变script
标签的位置
window.onload
,是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、css文件等),就调用处理函数。
一般来说,我们需要按照先写标签,然后将script
标签写在标签的下面的方式,但是我们可以通过window.onload
来改变script
标签的位置,因为这个方法会在页面加载完毕之后才执行,所以执行这个方法的时候,页面中的DOM元素已经全部被渲染了,请看下面示例。
<body><script>window.onload = function () {var btn = document.querySelector('button');btn.addEventListener('click',function () {alert('你点我?');})}</script><button>点击</button>
</body>
在以上代码中,我们没有按照之前的标准,将script
标签写在button
标签下面,但是依旧是可用的。
通过监听事件的方式写多个load
如果页面中存在多个
window.onload
,会以最后一个为准(最后一个会覆盖前面的事件)这是传统事件存在的弊端,为了解决这一问题,我们可以使用监听事件替换
window.onload
,请看下面示例。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>页面加载事件|侦听</title><script>window.addEventListener('load',function () {var btn2 = document.querySelector('#btn2');btn2.onclick = function () {alert('点击了按钮2');}})</script>
</head>
<body><script>window.addEventListener('load',function () {var btn1 = document.querySelector('#btn1');btn1.onclick = function () {alert('点击了按钮1');}})</script><button id="btn1">btn1</button><button id="btn2">btn2</button>
</body>
</html>
上面代码中,我们添加了两个window的侦听事件,验证得知两个侦听事件都生效了。
通过DOMContentLoaded
事件来获取窗口加载事件
document.addEventListener('DOMContentLoaded',function () {})
DOMContentLoaded
事件触发时,仅当DOM加载完成,不包括样式表、图片、flash等。IE9以上才支持。若果页面的图片非常多,那么推荐使用这种方式。
<body><script>window.addEventListener('load',function () {alert(22);})document.addEventListener('DOMContentLoaded',function () {alert(33);})</script>
</body>
以上代码一定是先弹出33再弹出22的,因为
DOMContentLoaded
事件只需要DOM元素加载完毕就可以执行,但是load
需要加载完成图片等各种信息之后才执行。
窗口大小变化事件
window.onresize = functoin(){}
window.addEventListener('resize',function () {} )
只要窗口大小发生变化,就会触发里面的处理函数。
<body><button>当宽度小于900px的时候,我就消失啦</button><script>window.addEventListener('resize',function () {// console.log('变化了');// console.log('内高:'+window.innerHeight+'\t内宽' + window.innerWidth);var btn = document.querySelector('button');if ( window.innerWidth < 900 ) {btn.style.display = 'none';} else {btn.style.display = 'block';}})</script>
</body>
以上代码的执行效果:当我们改变浏览器框的大小的时候,当宽度小于900px,这个button
按钮就会消失。
这种效果常用在一些页面元素渲染上,比如原本有四个列的某种元素,但是当页面较窄的时候,我们会隐藏其中某个列,以保证页面的正常显示。
回调函数
setTimeout()
这个函数我们称为回调函数 callback普通函数是按照顺序直接调用的,但是回调函数不按顺序来,比如定时器函数需要等待时间,等其它事情干完或者到了调用条件才会调用这个函数。
之前学习的
onclick
函数或者element.addEventListener('xxx',fun)
里面的函数也是回调函数。
setTimeout
定时器
setTimeout()
定时器window.setTimeout(调用函数,[延迟的毫秒数]);
window
在调用的时候可以省略- 单位是毫秒,省略是0秒,也就是立马执行
- 这个调用函数可以直接写函数,还可以写函数名(不需要带括号)
当延迟的毫秒数到了,就去执行函数。
定时器函数的使用
通过匿名函数调用
<body><script>// 单位是毫秒,省略是0秒,也就是立马执行setTimeout(function () {alert('我是Jim.kk');},2000);</script>
</body>
以上代码在页面加载出来两秒后会跳出弹窗提示。
通过函数名调用
<body><script>function fun() {alert('我是Jim.kk');}setTimeout(fun,2000);</script>
</body>
通过函数名字符串调用 | 不推荐
函数名字符串必须要加括号
以下代码与上面两个代码段执行无异,不多赘述
<body><script>function fun2() {alert('我是Jim.kk');}setTimeout('fun2()',2000);</script>
</body>
区分不同的定时器
以下代码会在页面加载出来后的两秒在控制台输出一句话,页面加载好的5秒后又会输出一句话。
<body><script>function fun3() {console.log('我是Jim.kk');}var timer1 = setTimeout(fun3,2000);var timer2 = setTimeout(fun3,5000);</script>
</body>
清除定时器
使用
clearTimeout(定时器名称)
函数可以清除定时器,请看如下代码注意,括号内是定时器的名称,不是字符串
<body><button>点我清除定时器</button><script>var btn = document.querySelector('button');var timer1 = setTimeout(function () {alert('我是Jim.kk');},5000);btn.onclick = function () {clearTimeout(timer1);}</script>
</body>
以上代码在弹窗出现之前若是点击了按钮,弹窗则永远也不会跳出来。
setInterval()
定时器
window.setInterval(回调函数,[间隔毫秒数])
- 与
setTimeout()
不同的是,setTimeout
只会执行一次,但是setInterval
会循环执行
setInterval()
的使用
<body><script>setInterval(function () {console.log('我是Jim.kk');},1000)</script>
</body>
以上代码每过一秒就会输出一次
我是Jim.kk
;
清除定时器 setInterval()
以下代码点击开始后开始循环(1秒1次)输出当前时间戳,点击停止后停止输出。
<body><button id="begin">开始</button><button id="stop">停止</button><script>var begin = document.querySelector('#begin');var stop = document.querySelector('#stop');var timer = null;begin.addEventListener('click',function () {setInterval(function () {console.log(+new Date());},1000);})stop.addEventListener('click',function () {clearInterval(timer);})</script>
</body>
this指向问题
总结起来一句话,谁调用,就指向谁。
- 全局作用下指向
window
- 全局作用域的方法中指向
window
(因为是window调用的方法)- 在定时器中指向
window
(因为定时器也是window调用的)- 在对象中指向这个对象
- 在事件中指向被触发事件(如被点击)的元素(如按钮)
- 如果在按钮点击事件中调用计时器,计时器中指向的还是
window
- 构造函数,指向的是实例对象
- 全局作用域下指向
window
<body><script>console.log(this); // window</script>
</body>
- 全局作用域的方法中指向
window
<body><script>function fun(){console.log(this);}fun(); // windowwindow.fun(); // 这行代码与上一行等效</script>
</body>
- 在定时器中指向
window
<body><script>setTimeout(function () {console.log(this); // window},1000);</script>
</body>
- 在对象中指向这个对象
<body><script>var o = {sayHi: function () {console.log(this); // o对象}}o.sayHi(); // o 对象</script>
</body>
- 在事件中指向被触发事件(如被点击)的元素(如按钮)
<body><button>点我</button><script>var btn = document.querySelector('button');btn.onclick = function () {console.log(this); // <button>点我</button>}</script>
</body>
- 如果在按钮点击事件中调用计时器,计时器中指向的还是
window
<body><button>点我</button><script>var btn = document.querySelector('button');btn.onclick = function () {setTimeout(function () {console.log(this); // 指向 window},1000)}</script>
</body>
- 构造函数,指向的是实例对象
<body><script>function Fun() {console.log(this); // 指向的是fun实例对象}var fun = new Fun();</script>
</body>
location
对象
location
相关属性与方法
window对象给我们提供了一个
location
属性用于获取或设置窗体的URL,并且可以用于解析URL。因为这个属性返回的是一个对象,所以我们将这个属性称为location对象。
location对象属性 | 返回值 |
---|---|
location.href | 获取或者设置整个URL |
location.host | 返回主机(域名) |
location.port | 返回端口号,如果未写返回空字符串 |
location.pathname | 返回路径 |
location.search | 返回参数 |
location.hash | 返回片段#后面内容,常见于链接、锚点 |
location方法 | 行为描述 |
---|---|
location.assign() | 记录历史并跳转 |
location.replace() | 不记录历史并跳转 |
location.reload() | 重载页面,如果页面里参数是true,则强制刷新,强制刷新不会保留缓存(Ctrl+F5 ) |
可以直接在控制台输入
location
点回车,查看当前的location。
下面实现一个点击按钮后五秒钟倒计时跳转百度的示例
<body><button>点我跳转</button><div></div><script>var btn = document.querySelector('button');var div = document.querySelector('div');btn.onclick = function () {var timer = 5;div.innerText = '将在' + timer +'秒后跳转至百度';setInterval(function (){timer -- ;if(timer === 0){location.href = 'https://baidu.com';} else {div.innerText = '将在' + timer +'秒后跳转至百度';}},1000);}</script>
</body>
以上代码在点击按钮后,会开始执行计时器,然后div中每次显示倒计时的时间,等时间到了,就会跳转到百度。
navigator
对象获取浏览器信息
navigator
对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent
,该属性可以返回由客户机发送服务器的user-agent
头部的值。
输出用户当前使用的客户端
alert(navigator.userAgent);
历史记录
forward()
前进 与 back()
后退
可以在括号中写上数字,控制前进后退的步数
要有历史记录(或者前进记录)的情况下才可以调用
以下写两个页面演示一下,命名如下:
- index页:``
- home页:
_BOM_06.6-home.html
<body><a href="_BOM_07.2-home.html">前往Home页</a><button>点我下一步</button><script>var btn = document.querySelector('button');btn.onclick = function (){history.forward();}</script>
</body>
<body><a href="_BOM_07.1-index.html">前往首页</a><button>点我返回</button><script>var btn = document.querySelector('button');btn.onclick = function (){history.back();}</script>
</body>
这样的话两个页面分别就有两个标签,在首页点击a标签之后进入到home页面,这时候就产生了历史记录,可以点击返回按钮返回,返回之后又可以点击下一步再次进入到首页。
可以在括号中写上数字,控制前进后退的步数
页面偏移量 offsetLeft 与 offsetTop
与style
的区别
offset
系列的返回值都是没有单位的,是一个纯数字,style
可以offset
不可以被赋值,style
可以offset
返回的宽度等信息包含padding
、border
、width
的宽度和高度,style
不包含
offsetLeft
与 offsetTop
- 返回的都是距离可视窗口(页面部分)左上角的定位
- 返回值是一个数字
- 不可以进行赋值
offsetWidth
与offsetHeight
- 返回的是宽度和高度
- 包含
padding
、border
、width
的宽度和高度- 如果元素的宽度是xx%,那么当浏览器大小发生变化时,该值也会动态发生变化
- 返回值是一个数字
offsetParent
- 返回的是父元素
- 如果父亲不带有定位,那么则会逐级向上找,直到找到带定位的元素(这是与
fatherNode
的区别)
以下代码的页面显示效果与控制台输出效果如下图所示:
<head><meta charset="UTF-8"><title>页面偏移量</title><style>body {width: 100%;height: 100%;margin: 0;}#father {position: relative;margin-top: 400px;margin-left: 800px;background: antiquewhite;width: 200px;height: 200px;border: .1px solid red;}#son {background: aqua;width: 100px;height: 100px;margin: 50px;}</style>
</head>
<body><div id="father"><div id="son"></div></div><script>var father = document.querySelector('#father');var son = document.querySelector('#son');console.log(father.offsetLeft); // 800console.log(father.offsetTop); // 400// 页面的宽度包含padding、border、width// 如果高度或者宽度是100%,那么当浏览器窗口大小变化的时候,这个值也会动态变化console.log(father.offsetWidth); // 200console.log(father.offsetHeight); // 200// 如果father带有定位(position: relative;),那么将会显示father,如果直接的father不带有定位,则逐级向上寻找,直到找到带定位的console.log(son.offsetParent);</script>
</body>
client
系列
与offset最大的区别就是不包含边框
client系列属性 | 说明 |
---|---|
element.clientTop | 返回元素上边框的大小 |
element.clientLeft | 返回元素左边框大小 |
element.clientWidth | 返回自身包含padding、内容区的宽度,不包含边框,返回一个数值 |
element.clientHeight | 返回自身包含padding、内容区的高度,不包含边框,返回一个数值 |
<head><meta charset="UTF-8"><title>client | 系列页面偏移量</title><style>div {width: 200px;height: 200px;background: pink;border: 3px solid red;margin: 200px auto;}</style></head>
<body><div></div><script>var div = document.querySelector('div');console.log(div.clientHeight); // 200console.log(div.clientWidth); // 200console.log(div.clientTop); // 3console.log(div.clientLeft); // 3</script>
</body>
注意:无法获取下边框与右边框大小
scroll
系列
scroll
属性
scroll
系列与offset
系列和client
系列最大的区别在于,如果元素内部的内容溢出了(如文字长度溢出或者内部div高度比当前元素高),那么scroll
显示的实际的高度和宽度。
scorll系列属性 | 说明 | 备注 |
---|---|---|
element.scrollTop | 返回被卷去的上侧距离 | 返回值不带参数 |
element.scrollLeft | 返回被卷去的左侧距离 | 返回值不带参数 |
element.scrollWidth | 返回自身实际的宽度,不含边框 | 返回值不带参数 |
element.scrollHeight | 返回自身实际的高度,不含边框 | 返回值不带参数 |
横向超出一样的道理
scroll
方法
div.addEventListener('scroll',function (){console.log(div.scrollTop)
})
当滚动条发生变化时触发
注意:当调用对象是
document
的时候,要使用window.pageYOffset
,如果要计算左侧则是window.pageXOffset
简单解释一下:我们上面说的
scroll
系列应对的是页面内的元素,比如页面内有一个小div
内部又套了一个div
,这时候要使用scroll
系列,但是操作document
的时候,操作的是整个页面,我们要使用windows.pageX/YOffset
。
移动端事件
触屏touch事件 | 说明 |
---|---|
touchstart | 手指触摸到一个DOM元素时触发 |
touchmove | 手指在一个DOM元素上滑动时触发 |
touchend | 手指离开一个DOM元素时触发 |
示例:写一个DIV,在移动端分别进行手指触摸、手指移动和手指离开操作
<head><meta charset="UTF-8"><title>移动端touchstart事件</title><style>div {width: 300px;height: 300px;background: pink;}</style>
</head>
<body><div></div><script>var div = document.querySelector('div');div.addEventListener('touchstart',function (e) {console.log('手指摸上去了');})div.addEventListener('touchmove',function (e) {console.log('手指正在移动');})div.addEventListener('touchend',function (e) {console.log('手指离开了');})</script>
</body>
以上代码的测试结果如下图所示:
如果要自己测试,记得F12并按照红色箭头方向打开移动端模式。
触摸时间对象
touchs
:正在触摸屏幕的所有手机的列表(是一个列表,由于可以多指触摸,所以是一个列表)targetTouches
:正在触摸当前DOM元素伤的手指列表changedTouches
:手指状态发生了改变的列表,从无到有,从有到无的变化
本地存储
sessionStorage
:生命周期为关闭浏览器窗口,同页面下数据可以共享(关闭页面或新建页面后失效),以键值对存储,存储空间约5MsessionStorage
:多页面(同一浏览器内)共享(重启浏览器依旧生效),不同页面的数据可以共享,以键值对存储,存储空间约20M
sessionStorage
sessionStorage方法 | 说明 | 备注 |
---|---|---|
setItem(‘key’,value) | 存储一个数据 | 存储空间约5M |
getItem(‘key’) | 使用key获取一个数据 | |
removeItem(‘key’) | 删除一个数据 | |
clear() | 清空所有数据 |
localStorage
localStorage方法 | 说明 | 备注 |
---|---|---|
setItem(‘key’,value) | 存储一个数据 | 存储空间约20M |
getItem(‘key’) | 使用key获取一个数据 | |
removeItem(‘key’) | 删除一个数据 | |
clear() | 清空所有数据 |