BOM 概述

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

1. DOM

  • 文档对象模型
  • DOM 就是把文档当做一个对象来看待
  • DOM 的顶级对象是 document
  • DOM 主要学习的是操作页面元素
  • DOM 是 W3C 标准规范

2. BOM

  • 浏览器对象模型
  • 把浏览器当做一个对象来看待
  • BOM 的顶级对象是 window
  • BOM 学习的是浏览器窗口交互的一些对象
  • BOM 是浏览器厂商在各自浏览器上定义的,兼容性较差

window 对象的常见事件

window.onload = function() {};
window.addEventListener("load", function() {});

window.onload 是窗口加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、css 文件等)

  1. 有了 window.onload 就可以把 JS 代码写到页面元素的上方,因为是等页面内容全部加载完毕再去执行处理函数
  2. window.onload 传统注册事件方式只能写一次,如果有多个,会以最后一个 window.onload 为准
  3. 如果使用 addEventListener 则没有限制

窗口加载事件

document.addEventListener('DOMContentLoaded', function() {})

DOMContentLoaded 事件触发时,仅当 DOM 加载完成,不包括样式表,图片,flash 等

调整窗口大小事件

window.onresize = function() {};
window.addEventListener('resize', function() {});
  1. 只要窗口大小发生像素变化,就会触发这个时间
  2. 我们经常利用这个事件完成响应式布局,window.innerWidth 当前屏幕的宽度

定时器

window 对象给我们提供了 2 个非常好用的方法-定时器

  • setTimeout()
  • setInterval()

setTimeout()

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

该定时器在定时器到期后执行调用函数,注意:

  1. window 可以省略
  2. 这个调用函数可以直接写函数,或者写函数名
  3. 延迟的毫秒数省略默认是 0
  4. 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符

setTimeout() 这个调用函数我们也称为回调函数 callback(等时间到了才会去调用这个函数)
element.onclick = function() {};或者 element.addEventListener('click', function() {}); 里面的函数也是回调函数

1
2
3
4
5
// 5秒之后自动关闭广告
var ad = document.querySelector('.ad');
setTimeout(function () {
ad.style.display = 'none';
}, 5000);

停止 setTimeout()

window.clearTimeout(timeoutID)

里面的参数就是定时器的标识符

setInterval()

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

该方法重复调用一个函数,每隔一段时间,就去调用一次回调函数

停止 setInterval()

window.clearInterval(intervalID)

里面的参数就是定时器的标识符

this

this 的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定 this 到底指向谁,一般情况下 this 的最终指向的是那个调用它的对象

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

location 对象

URL 的一般语法格式为:

protocol://host[:port]/path/[?query]#fragment
https://127.0.0.1:4000/posts/de3efe0d.html#setTimeout
组成说明
protocol通信协议,常用的有 http,ftp,mailto 等
host主机(域名)
port端口号(可选)
path路径,由零或多个'/'符号隔开的字符串
query参数,以键值对的形式,通过'&'符号分割开
fragment片段,#后面的内容,常见于链接锚点

location 对象的属性

location 对象属性返回值
location.href获取或者设置整个 URL
location.host返回主机(域名)
location.port返回端口号,如果没写则返回空字符串
location.pathname返回路径
location.search返回参数
location.hash返回片段

location 对象的方法

location 对象方法返回值
location.assign()跟 href 一样,可以跳转页面(重定向)
location.replace()替换当前页面,因为不记录历史,所以不能后退页面
location.reload重新加载页面,相当于刷新按钮或者 f5,如果参数为 true,即强制刷新 ctrl+f5

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

1
2
3
4
5
6
7
8
9
if (
navigator.userAgent.match(
/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
)
) {
window.location.href = ''; //手机
} else {
window.location.href = ''; //电脑
}

history 对象

我们可以使用 history 对象与浏览器历史记录进行交互,该对象包含用户访问过的 URL

history 对象方法作用
back()后退
forward()前进
go(参数)参数如果是 1 前进 1 个页面,如果是-1 后退 1 个页面

元素偏移量 offset

使用 offset 系列相关属性可以动态的得到该元素的位置、大小等

  • 获得元素距离带有定位父元素的位置
  • 获得元素自身的大小
  • 返回的数值不带单位
offset 系列属性作用
element.offsetParent返回作为该元素带有定位的父级元素,如果父级都没有定位,则返回 body
element.offsetTop返回元素相对带有定位的父元素上方的距离
element.offsetLeft返回元素相对带有定位的父元素左边框的距离
element.offsetWidth返回自身包括 padding、边框、内容区的宽度,返回数值不带单位
element.offsetHeight返回自身包括 padding、边框、内容区的高度,返回数值不带单位

offset 与 style 的区别

1. offset

  • offset 可以得到任意样式表中的样式值
  • offset 系列获得的数值是没有单位的
  • offsetWidth 包含 padding + border + width
  • offsetWidth 等属性是只读属性,只能获取不能赋值
  • 想要获取元素大小位置,用 offset 更合适

2. style

  • style 只能得到行内样式表中的样式值
  • style.width 获得的是带有单位的字符串
  • style.width 不包含 padding 和 border
  • style.width 是可读写属性,可以赋值
  • 想要给元素更改值,用 style 更合适

元素可视区 client

通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等

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

元素滚动 scroll

使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等

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

三大系列小结

  1. offset 系列经常用语获得元素位置 offsetLeft、offsetTop
  2. client 系列经常用于获取元素大小 clientWidth、clientHeight
  3. scroll 系列经常用于获取滚动距离 scrollTop、scrollLeft
  4. 注意页面滚动的距离通过window.pageYOffset获得

mouseenter 和 mouseover

  • mouseenter 不会冒泡
  • mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发
  • mouseenter 只会在鼠标经过自身盒子时触发
  • mouseleave 同样不会冒泡(和 mouseout 对比)

触屏事件

触屏 touch 事件说明
touchstart手指触摸到一个 DOM 元素时触发
touchmove手指在一个 DOM 元素上滑动时触发
touchend手指从一个 DOM 元素上移开时触发

触摸事件对象

TouchEvent 是一类描述手指在触摸平面的状态变化事件

触摸列表说明
touches正在触摸屏幕的所有手指的一个列表
targetTouches正在触摸当前 DOM 元素上的手指的一个列表
changedTouches手指状态发生了改变的列表,从无到有,从有到无变化

移动端拖动元素

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
// (1) 触摸元素 touchstart:  获取手指初始坐标,同时获得盒子原来的位置
// (2) 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子
// (3) 离开手指 touchend:
var div = document.querySelector('div');
var startX = 0; //获取手指初始坐标
var startY = 0;
var x = 0; //获得盒子原来的位置
var y = 0;
div.addEventListener('touchstart', function (e) {
// 获取手指初始坐标
startX = e.targetTouches[0].pageX;
startY = e.targetTouches[0].pageY;
x = this.offsetLeft;
y = this.offsetTop;
});

div.addEventListener('touchmove', function (e) {
// 计算手指的移动距离: 手指移动之后的坐标减去手指初始的坐标
var moveX = e.targetTouches[0].pageX - startX;
var moveY = e.targetTouches[0].pageY - startY;
// 移动我们的盒子 盒子原来的位置 + 手指移动的距离
this.style.left = x + moveX + 'px';
this.style.top = y + moveY + 'px';
e.preventDefault(); // 阻止屏幕滚动的默认行为
});

classList 属性

该属性用于在元素中添加,移除和切换 CSS 类名

1
2
3
4
5
6
7
8
element.classList.add('类名');
// focus.classList.add('current');

element.classList.remove('类名');
// focus.classList.remove('current');

element.classList.toggle('类名');
// focus.classList.toggle('current');

click 延时解决方案

移动端 click 事件会有 300ms 的延时,原因是移动端双击屏幕会缩放页面

  1. 禁用缩放
  2. 利用 touch 事件自己封装这个事件解决 300ms 延迟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//封装tap,解决click 300ms 延时
function tap(obj, callback) {
var isMove = false;
var startTime = 0; // 记录触摸时候的时间变量
obj.addEventListener('touchstart', function (e) {
startTime = Date.now(); // 记录触摸时间
});
obj.addEventListener('touchmove', function (e) {
isMove = true; // 看看是否有滑动,有滑动算拖拽,不算点击
});
obj.addEventListener('touchend', function (e) {
if (!isMove && Date.now() - startTime < 150) {
// 如果手指触摸和离开时间小于150ms 算点击
callback && callback(); // 执行回调函数
}
isMove = false; // 取反 重置
startTime = 0;
});
}
//调用
tap(div, function () {
// 执行代码
});
  1. 使用插件 fastclick

移动端常用开发插件

  1. https://www.swiper.com.cn/
  2. http://www.superslide2.com/
  3. https://github.com/cubiq/iscroll

本地存储

  1. 数据存储在用户浏览器中
  2. 设置、读取方便、甚至页面刷新不丢失数据
  3. 容量较大、sessionStorage 约 5M、localStorage 约 20M
  4. 只能存储字符串、可以将对象 JSON.stringify()编码后存储

window.sessionStorage

  1. 生命周期为关闭浏览器窗口
  2. 在同一个窗口下数据可以共享
  3. 以键值对的形式存储使用
1
2
3
4
5
6
7
8
9
10
11
// 存储数据
sessionStorage.setItem(key, value);

// 获取数据
sessionStorage.getItem(key);

// 删除数据
sessionStorage.removeItem(key);

// 清空数据
sessionStorage.clear();

window.localStorage

  1. 生命周期永久有效,除非手动删除,否则关闭页面也会存在
  2. 可以多窗口共享(同一浏览器)
  3. 以键值对的形式存储使用
1
2
3
4
5
6
7
8
9
10
11
// 存储数据
localStorage.setItem(key, value);

// 获取数据
localStorage.getItem(key);

// 删除数据
localStorage.removeItem(key);

// 清空数据
localStorage.clear();

记住用户名案例

1
2
3
4
5
6
7
8
9
10
11
12
13
var username = document.querySelector('#username');
var remember = document.querySelector('#remember');
if (localStorage.getItem('username')) {
username.value = localStorage.getItem('username');
remember.checked = true;
}
remember.addEventListener('change', function () {
if (this.checked) {
localStorage.setItem('username', username.value);
} else {
localStorage.removeItem('username');
}
});

综合案例-轮播图