# JavaScript BOM 基础部分

BOM (Browser Object Model), 即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心是 window

image-20220324192211016

window 对象是浏览器的顶级对象,它具有双重角色

  • 他是 JS 访问浏览器窗口的一个接口
  • 它是一个全局对象,定义在全局作用域中的变量,函数都会变成 window 对象的属性和方法

# window 对象的常见对象

# 窗口加载事件

window.onload 是窗口 (页面) 加载事件,, 当文档内容完全加载完成会触发该事件 (包括图像,脚本文件,CSS 文件等), 就调用的处理函数

注意 :

  • 有了 window.onload 就可以把 JS 代码写到网页元素的上方,因为 onload 是等页面内容全部加载完毕,再去执行处理函数
  • window.onload 传统注册事件只能写一次,如果有多个,会以最后一个 window.onload 为准
1
2
3
window.addEventListener('load', function () {
alert('hello');
})

DOMContentLoaded 事件触发时,仅当 DOM 加载完成,不包括样式表,图片,flash 等等 (IE9 以上支持)

如果页面的图片很多的话,从用户访问当 onlick 触发可能需要较长的时间,必然影响用户的体验,此时用 DOMContentLoaded 时间比较合适

1
2
3
window.addEventListener('DOMContentLoaded', function () {
alert('no hello');
})

# 调整窗口大小事件

window.onresize 是调整窗口大小加载事件,当触发时就调用的处理函数

注意 :

  • 只要窗口大小发生像素变化,就会触发这个事件
  • 我们经常利用这个事件完成响应式布局, window.innerWidth 当前屏幕的宽度
1
2
3
4
5
6
7
8
9
var div = document.querySelector('div');
window.addEventListener('resize', function () {
console.log(innerWidth);

if (innerWidth < 400)
div.style.display = 'none';
else
div.style.display = 'block';
})

# 定时器

window 对象给我们提供了 2 个定时器 : setTimeout() , setInterval()

# setTimeout () 定时器

window.setTimeout (调用函数,[延迟的毫秒数]);

该定时器在定时器到期后执行调用函数

注意 :

  • window 可以省略
  • 这个调用函数可以直接写函数,或者写函数名或者采用字符串,== 函数名 ()== 三种形式,第三种不推荐
  • 延迟的毫秒数省略默认是 0, 如果写,必须是毫秒
  • 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
1
2
3
4
var timer = setTimeout(function () {
var div = document.querySelector('div');
div.style.display = 'none';
}, 5000)

window.clearTimeout(timeoutID)

停止 setTimeout () 定时器

注意 :

  • window 可以省略
  • 里面的参数就是定时器的标识符
1
2
3
button.addEventListener('click', function () {
clearTimeout(timer);
})

# setInterval () 定时器

window.setInterval (回调函数,[间隔的毫秒数]);

setInterval () 方法重复调用一个函数,每隔这个事件,就去调用一次回调函数

注意 :

  • window 可以省略
  • 这个调用函数可以直接写函数,或者写函数名或者采取字符串 函数名() 三种形式
  • 间隔的毫秒数省略默认是 0, 如果写,必须是毫秒,表示每个多少毫秒就自动调用这个函数
  • 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
1
2
3
var timer setInterval(function () {
console.log('继续输出');
}, 1000)

window.clearInterval(intervalID);

通过取消了先前通过调用 setTinterval () 建立的定时器

注意 :

  • window 可以省略
  • 里面的参数就是定时器的标识符

# this 指向问题

  • 全局作用域或者普通函数中 this 指向全局对象 window ( 注意定时器里面的 this 指向 window)
  • 方法中的 this 指向调用这个方法的对象
  • 构造函数中的 this 指向实例对象

# JS 执行机制

# JS 单线程

JavaScript 语言的一大特点就是单线程,也就是说,同一个事件只能做一件事,这是因为 JavaScript 这门脚本语言诞生的使命所致 ——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的,比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行,应该先进行添加,之后再删除

# 同步和异步

为了解决这个问题,利用多喝 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,于是 JS 中出现了同步异步

同步 前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的,同步的

异步 在做一件事时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情

img

同步任务

  • 都在主线程上执行,形成一个执行栈

异步任务

JS 的异步任务通过回调函数实现

一般而言,异步任务有以下三种类型

  • 普通事件,如 click , resize
  • 资源加载,如 load , error
  • 定时器,包括 setTimeout , setInterval

异步任务相关回调函数添加到任务队列中 (任务队列也成为消息队列)

# JS 执行顺序

  1. 限制性执行栈中的同步任务
  2. 异步任务 (回调函数) 放入任务队列中
  3. 一旦执行栈的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行

由于主线程不断地重复获取任务,执行任务,再获取任务,再执行,所以这种机制被称为事件循环 (event loop)

# location 对象

window 对象提供了一个 location 属性用于获取或设置窗体的 URL, 并且可以用于解析 URL, 因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象

统一资源定位符 (Uniform Resource Locator, URL) 是互联网上标准资源的地址,互联网上的每个文件都有一个唯一的的 URL, 它包含的信息指出文件的位置以及浏览器应该怎么处理它

URL 一般的语法格式为 :

protocol://host[:port]/path/[?query]#fragment

组成说明
protocol通信协议 常用的 http, https, maito 等
host主机 (域名) www.baidu.com
port端口号 可选,省略是使用方案默认的窗口,如 http 默认窗口为 80
path路径 由 零或多个 '/' 字符隔开的字符串,一般用来表示主机上的一个目录或者文件地址
query参数 以键值对的形式,通过 & 符号分隔开来
fragment片段 #后面内容 常见于链接

# location 对象的属性

location 对象属性返回值
location.href获取或者设置整个 URL
location.host返回主机 (域名)
location.port返回端口号,如果未写返回空字符串
location.pathname返回路径
location.search返回参数
location.hash返回片段 #后面内容 常见于链接 锚点

重点记住 : href 和 search

# assign

重定向页面,浏览器可以保存重定向之前的页面,也就是说可以后退到上一个页面

1
2
3
setTimeout(function () {
location.assign('https://weibo.com')
} ,5000)

# replace

重定向页面,浏览器不会保存浏览历史

1
2
3
setTimeout(function () {
location.replace('https://weibo.com');
}, 3000)

# reload

重新加载页面,相当于刷新按钮或按 F5, 如果参数为 true, 强制刷新 CTRL + F5

1
2
location.reload();
location.reload(true); //强制刷新

navigator 对象包含有关浏览器的信息,它由很多属性,我们最常用的是 userAgent , 该属性可以返回由客户机发送服务器的 user-agent 头部的值

# history 对象

window 对象提供了一个 history 对象,与浏览器历史记录进行交互,该对象包含用户 (在浏览器窗口中) 访问过的 URL

history 对象方法作用
back()可以后退功能
forward()前进功能
go (参数)前进后退功能,参数如果是 1, 前进一个页面,如果是 - 1, 后退一个页面
1
2
3
4
5
6
7
8
9
10
11
12
var btns = document.querySelectorAll('button');
btns[0].addEventListener('click', function () {
history.forward();
});

btns[1].addEventListener('click', function () {
history.back();
});

btns[2].addEventListener('click', function () {
history.go(2);
});

# 网页特效

# offsetLeft 和 offsetTop 获取元素偏移量

offset 翻译过来就是偏移量,使用 offset 系列相关属性可以动态的得到该元素的位置 (品阿姨), 大小等

  • 获得元素距离带有定位父元素的位置
  • 获得元素自身的大小 (宽度高度)

注意 : 返回的数值都不带单位

offset 系列常用属性 :

offset 系列属性作用
element.offsetParent返回作为该元素带有定位的父级元素,如果父级没有定位则返回 body
element.offsetTop返回元素相对带有定位父元素上方的偏移
element.offsetLeft返回元素相对带有定位父元素左边框的偏移
element.offsetWidth返回子升包括 padding, 边框,内容区的宽度,返回数值不带单位
element.offsetHeight返回自身包括 padding 边框,内容区的高度,返回数值不带单位

如果父元素的样式表中没有 position 属性说明位置的话,则默认显示子元素的绝对偏移量,如果父元素中有的话,则显示子元素相对于父元素的相对偏移量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.father {
width: 300px;
height: 300px;
background-color: pink;
margin: 100px;
position: relative;
}

.son {
width: 200px;
height: 200px;
margin: auto;
background-color: orange;
border: 1px solid black;
}

var father = document.querySelector('.father');
var son = document.querySelector('.son');
console.log(son.offsetLeft); //返回50, 因为father中含有position属性
console.log(son.offsetWidth); //返回202, 因为左右边框占2个像素, 且没有box-sizing属性
console.log(son.offsetHeight); //返回202, 因为上下边框占2个像素, 且没有box-sizing属性
console.log(son.offsetParent); //返回 div.box 这个父级对象

offset 和 style 的区别

offsetstyle
offset 可以得到任意样式表中的样式值style 只能得到行内样式表中的样式值
offset 系列获得的数值是没有单位的style.width 获得的是由单位的字符串
offsetWidth 包含 padding + border + widthstyle.width 获得不包含 padding 和 border 的值
offsetWidth 等属性是只读属性,只能获取不能赋值style.width 是可读属性,可以获取也可以赋值
所以,如果想要获取元素大小位置,使用 offset 更佳合适所以,如果想要给元素更改值,则需要 style 改变

# 获取鼠标在盒子内的坐标

1
2
3
4
5
var father = document.querySelector('.father');
father.addEventListener('click', function (e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
console.log(x + ',' + y);

# 元素可视区 client 系列

client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息,通过 client 系列的相关属性可以动态的得到元素的边框大小,元素大小等

client 系列属性作用
element.clientTop返回元素上边框的大小
element.clentLeft返回元素左边框的大小
element.clientWidth返回自身包括 padding, 内容区的宽度,不含边框,返回数值不带单位
element.clientHeight返回自身包括 padding, 内容区的高度,不含边框,返回数值不带单位

client 翻译过来就是客户端。我们使用 client 系列的相关属性来获取元素可视区的相关信息,通过 client 系列的相关属性可以动态的得到该元素的边框大小,元素大小等

# 立即执行函数

立即执行函数:不需要调用,立马能够自己执行的函数

(function(){}())(function(){})()

立即函数最大的作用就是:独立创建了一个作用域,里面所有的变量都是局部变量,不会有命名冲突的情况

# 淘宝 flexible.js 源码解析

以下三种情况都会刷新页面都会触发 load 事件

  • a 标签的超链接
  • F5 或者刷新按钮 (强制刷新)
  • 前进后退按钮

但是在火狐中,有个 "往返缓存", 这个缓存中不仅保存着页面数据,还保存了 DOM 和 JavaScript 的状态,实际上是将整个页面都保存在了内存里

所以此时后退按钮不能刷新页面

此时可以使用 pageshow 事件来触发,这个事件在页面显示时触发,无论页面是否来自缓存,在重新加载页面中, pageshow 会在 load 事件触发后触发,根据事件对象中的 persisted 来判断是否缓存中的页面触发的 pageshow 事件,注意这个事件给 window 添加

persisted 属性是判断页面是否由缓存加载,是 为 true , 否 为 false

# scroll 系列书信

scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小,滚动距离等

scroll 系列属性作用
element.scrollTop返回被卷去的上侧距离,返回数值不带单位
element.scrollLeft返回被卷去的左侧距离,返回数值不带单位
element.scrollWidth返回自身实际的宽度,不含边框,返回数值不带单位
element.scrollHeight返回自身实际的高度,不含边框,返回数值不带单位

# 动画效果

定时器一般放在类里面,便于管理和区分,在设置定时器之前,消除此类之前存在的定时器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var move = function (obj, target) {
clearInterval(obj.timer); //清除之前的定时器
obj.timer = setInterval(function () { //在obj类中新建timer定时器
if (obj.offsetLeft >= target)
clearInterval(obj.timer);
else
obj.style.left = obj.offsetLeft + 1 + 'px';
},10)
}

move(moveBox, 700);
// move(span, 400);
var btn = document.querySelector('button');
btn.addEventListener('click', function () {
move(span, 700);

# 缓动效果

缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来

思路 :

  • 让盒子每次移动的距离慢慢变小,速度就会慢下来
  • 核心算法 : (目标值 - 现在位置) / 10 为每次移动的距离步长
  • 停止的条件:让当前盒子位置等于目标位置就停止定时器
1
2
3
4
5
6
7
8
9
var move = function (obj, target) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
if (obj.offsetLeft >= target)
clearInterval(obj.timer);
else
obj.style.left = obj.offsetLeft + (target - obj.offsetLeft) / 30 + 'px';
},10)
}

# 本地存储

# window.sessionStorage

  • 声明周期为关闭浏览器窗口
  • 在同一个窗口 (页面) 下数据可以共享
  • 以键值对形式储存使用

储存数据 :

sessionStorage.setItem(key, value)

获取数据 :

sessionStorage.getItem(key)

删除数据 :

sessionStorage.removeItem(key)

清空数据 :

sessionStorage.clear()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>本地存储</title>
</head>
<body>
<label>
<input type="text" placeholder="请输入名字">
<button class="set">存储</button>
<button class="get">取出</button>
<button class="remove">删除</button>
<button class="clean">重置</button>
</label>
</body>
<script>
var textBox = document.querySelector('input');
var set = document.querySelector('.set');
var get = document.querySelector('.get');
var remove = document.querySelector('.remove');
var clean = document.querySelector('.clean');

set.addEventListener('click', function () {
sessionStorage.setItem('uname', textBox.value);
});

get.addEventListener('click', function () {
console.log(sessionStorage.getItem('uname'));
});

clean.addEventListener('click', function () {
sessionStorage.clear();
})

remove.addEventListener('click', function () {
sessionStorage.removeItem('uname');
})
</script>
</html>

# window.localStorage

  • 生命周期永久生效,除非手动删除,否则关闭页面也会存在
  • 可以多窗口 (页面) 共享 (同一浏览器可以共享)
  • 以键值对的形式存储使用

存储数据 :

localStorage.setItem(key, value)

获取数据 :

localStorage.getItem(key)

删除数据 :

localStorage.removeItem(key)

清空数据 :

localStorage.clear()