3 BOM

3.1 概念

BOM是指浏览器对象模型
浏览器的对象模型提供了独立于内容的,可以与浏览器窗口进行互动的对象结构。
BOM由多个对象组成,其中代表浏览器窗口的Window对象是BOM的顶层对象,其他对象都是该对象的子对象

比如:刷新浏览器,后退,前进,在浏览器中输入URL等

window是浏览器的顶级对象,当调用window下的属性和方法时,可以省略window

我们定义的变量都是基于windows的

1
2
3
4
5
6
var abc="123";
function fn() {
console.log("fn")
}
console.log(window.abc)
window.fn();

注意:window下一个特殊的属性window.name无法被改变
window对象本身具有name和top两个属性,其中top属性是只读

3.2 对话框

  • alert() 弹出确定
  • prompt() 弹出是否
  • confirm() 弹出输入框
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
//====================== JS最常用三种弹出对话框 ========================  

//弹出对话框并输出一段提示信息
function ale() {
//弹出一个对话框
alert("提示信息!");

}

//弹出一个询问框,有确定和取消按钮
function firm() {
//利用对话框返回的值 (true 或者 false)
if (confirm("你确定提交吗?")) {
alert("点击了确定");
}
else {
alert("点击了取消");
}

}

//弹出一个输入框,输入一段文字,可以提交
function prom() {
var name = prompt("请输入您的名字", ""); //将输入的内容赋给变量 name ,

//这里需要注意的是,prompt有两个参数,前面是提示的话,后面是当对话框出来后,在对话框里的默认值
if (name)//如果返回的有内容
{
alert("欢迎您:" + name)
}

}

3.3 页面加载和关闭

  1. 页面加载完成后执行

onload

前面说过html是从上往下执行,如果把js写在hrad中,是获取不到页面中的元素的
不过加上页面加载后执行的方法就不一样了,可以吧js放到任意位置

页面加载完毕指的是:DOM元素加载完毕,并且外部文件加载完毕

1
2
3
4
5
// onload 页面加载完毕执行
onload = function() {
var box = document.getElementById("box");
console.log("box")
}

  1. 页面关闭时执行

    onunload

1
2
3
onunload = function() {
console.log("再见")
}

3.4 定时器

  1. setTimeout()和clearTimeout()
    在指定的行描述到到之后执行指定的函数,只执行一次
1
2
3
4
5
6
7
// 创建一个定时器,1000毫秒之后执行
var timerId = setTimeout(function() {
console.log("Hello")
},1000)

// 取消定时器的执行
clearTimeout(timerId);
  1. setInterval()和clearInterval()
    定时调用函数,可以按照给定的事件周期调用函数
1
2
3
4
5
6
7
// 创建一个定时器,1000毫秒之后执行
var timerId = Interval(function() {
console.log("Hello")
},1000)

// 取消定时器的执行
clearInterval(timerId);

案例:十秒后可以点击按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var btn = document.getElementById("btn");
var count = 10;
var timerId = setInterval(function() {
count -- ;
if(count > 0){
// 如果不到10秒,修改按钮上的数字
btn.value = "同意(请继续阅读"+count+"秒)";
}else{
// 时间到了
btn.value = "同意";
btn.disabled = false;
// 停止定时器
clearInterval(timerId);
}
},1000)

5秒后跳转

1
2
3
4
5
6
7
8
9
10
var timerId = setTimeout(function() {
// 5秒以后跳转
location.href = "www.baidu.com"
},5000);
console.log(timerId);

var btn = document.getElementById("btn");
btn.onclick = function() {
clearTimeout(timerId);
}

定时器是典型的异步编程:
在主线程还没有结束是不会调用其他线程的方法

3.5 内存中数据存储

  • 栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储
  • 堆内存存储的对象类型数据对于大小这方面,一般都是未知的

这也是为什么null作为一个object类型的变量却存储在栈内存中的原因。

一般来说栈内存线性有序存储,容量小,系统分配效率高。而堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中,效率相对就要低一些了。
垃圾回收方面,栈内存变量基本上用完就回收了,而推内存中的变量因为存在很多不确定的引用,只有当所有调用的变量全部销毁之后才能回收。

js中有四个基本类型的数据

  • 字符串
  • 数字
  • 布尔
  • null/undifind

他们的存储如图所示
如图所示

其他类型,如对象数组存储如下图
如图所示

const定义的基本类型不能改变,但是定义的对象是可以通过修改对象属性等方法来改变的。

3.6 移动div

.offsetLeft 左边距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 1. 注册事件
var btn = document.getElementById("btn");
var box = document.getElementById("box");

btn.onclick = function() {
// 2. 让BOX能往右移动
var timerId = setInterval(function() {
// 当前的left
var current = box.offsetLeft;
current +=8;

// 3. 停到指定位置500
if(current >=500){
clearInterval(timerId);
box.style.left = "500px";
return;
}
box.style.left = current+"px";
},30)
}

3.7 location对象

location对象是window对象下的一个属性,使用的时候可以省略window对象

location可以获取或者设置浏览器地址的URL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
console.log(location)
Location {replace: ƒ, assign: ƒ, href: "https://www.baidu.com/", ancestorOrigins: DOMStringList, origin: "https://www.baidu.com", …}
ancestorOrigins: DOMStringList {length: 0}
assign: ƒ ()
hash: ""
host: "www.baidu.com"
hostname: "www.baidu.com"
href: "https://www.baidu.com/"
origin: "https://www.baidu.com"
pathname: "/"
port: ""
protocol: "https:"
reload: ƒ reload()
replace: ƒ ()
search: ""
toString: ƒ toString()
valueOf: ƒ valueOf()
Symbol(Symbol.toPrimitive): undefined
__proto__: Location

location的几个方法

  • reload 重新加载
  • assign 跳转
  • replace 替换
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var btn = document.getElementById("btn");
    btn.onclick = function() {
    // 有一个参数
    // false 可能从缓存获取 F5
    // true 强制从服务器获取页面ctrl+r(ctrl+F5)
    // location.reload(true);

    // 跳转 会记录历史
    location.assign("http://www.baidu.com")

    // 替换地址栏中的地址 不会记录历史
    location.replace("http://www.baidu.com")
    }

3.8 history对象

  • back() // 后退
  • forward() // 前进
  • go() // 去哪页

  • go(-1): 返回上一页,原页面表单中的内容会丢失;

  • history.go(-1):后退+刷新;
  • history.go(1) :前进
  • back(): 返回上一页,原页表表单中的内容会保留;
  • history.back():后退 ;
  • history.back(0) 刷新;
  • history.back(1):前进

后退

1
2
3
4
var btn = document.getElementById("btn");
btn.onclick = function() {
history.back();
}

前进

1
2
3
4
var btn = document.getElementById("btn");
btn.onclick = function() {
history.forward();
}

3.9 navigator对象

Navigator 对象包含有关浏览器的信息。

  • userAgent 浏览器信息
    1
    2
    navigator.userAgent
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"

在浏览器发送请求的时候会发送给服务器

如图所示

如果调成手机模式会给服务器发送手机信息,服务器再判断是手机来源从而提供手机页面(在NGINX中有说明)

如图所示


3.9 offsetWidth和offsetLeft

如图所示

1
2
3
4
5
<body>
<div id="box1">
<div id="box2"></div>
</div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
var box2 = document.getElementById("box2");
// 内容 + border + padding
console.log(box2.offsetWidth);
console.log(box2.offsetHeight);

// 获取的相对于offserParent的距离
console.log(box2.offsetLeft);
console.log(box2.offsetTop);

// offsetParent 最近的脱离文档流的父元素,如果没有脱离文档流的父元素,就是body
console.log(box2.offsetParent);
console.log(box2.parentNode);

3.10 offset/scroll/client

  1. window相关宽高属性
  • window.outerHeight (窗口的外层的高度)

获取整个浏览器窗口的高度(单位:像素),包括侧边栏(如果存在)、窗口镶边(window chrome)和窗口调正边框。包含调试窗及浏览器边框

  • window.outerWidth (窗口的外层的宽度)

表示整个浏览器窗口的宽度,包括侧边栏(如果存在)、窗口镶边(window chrome)和调正窗口大小的边框。包含调试窗及浏览器边框

  • window.screen.width

声明了显示当前浏览器的屏幕的宽度,以像素计

  • window.screen.height

声明了显示当前浏览器的屏幕的高度,以像素计

如图所示

  1. offset

如图所示

如图所示

如图所示

如图所示

如图所示

oEvent.clientX是指鼠标到可视区左边框的距离。
oEvent.clientY是指鼠标到可视区上边框的距离。

offsetWidth是指div的宽度(包括div的边框)
offsetHeight是指div的高度(包括div的边框)
offsetLeft是指div到整个页面左边框的距离(不包括div的边框)
offsetTop是指div到整个页面上边框的距离(不包括div的边框)

scrollTop是指可视区顶部边框与整个页面上部边框的看不到的区域。
scrollLeft是指可视区左边边框与整个页面左边边框的看不到的区域。
scrollWidth是指左边看不到的区域加可视区加右边看不到的区域即整个页面的宽度(包括边框)
scrollHeight是指上边看不到的区域加可视区加右边看不到的区域即整个页面的高度(包括边框)

clientWidth是指可视区的宽度。
clientHeight是指可视区的高度。
clientLeft获取左边框的宽度。
clientTop获取上边框的宽度。

3.11 案例

公共方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 获取鼠标在页面上的坐标
function getPage(e){
return{
pageX:e.clientX + getScroll().scrollLeft,
pageY:e.clientY + getScroll().scrollTop
}
}

// 获取页面滚出去的距离(处理兼容性)
function getScroll() {
return{
scrollTop:document.documentElement.scrollTop || document.body.scrollTop,
scrollLeft:document.documentElement.scrollLeft || document.body.scrollLeft,
}
}

  1. 拖拽弹出框

user-select:none CSS样式文本不能被选择

1
2
3
4
5
6
7
8
<div class="nav">
<a href="javascript:;" id="register">注册信息</a>
</div>
<div class="d-box" id="d_box">
<div class="hd" id="drop">注册信息(可拖拽)
<span id="box_close">关闭</span>
</div>
</div>
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
var d_box = document.getElementById("d_box");
var drop = document.getElementById("drop");
// 1. 鼠标在box中的头部按下的时候,计算鼠标在盒子中的坐标
// 1.1 给头部注册鼠标按下的
drop.onmousedown = function(e) {
e = e || event;
// 1.2 计算鼠标在盒子中的坐标 = 鼠标在页面中的坐标 - 盒子在页面中的坐标
var x = getPage(e).pageX - d_box.offsetLeft;
var y = getPage(e).pageY - d_box.offsetTop;

// 鼠标在整个页面移动过程中,计算盒子在页面中的坐标
document.onmousemove = function(e) {
// 计算盒子在页面中的坐标 = 鼠标在页面上的坐标 - 鼠标在盒子中的坐标
var boxX = getPage(e).pageX - x;
var boxY = getPage(e).pageY - y;

d_box.style.left = boxX + "px";
d_box.style.top = boxY + 'px';
}
}

// 当鼠标弹起时,移除move事件
document.onmouseup = function() {
document.onmousemove = null;
}
  1. 点击弹出拖拽登录框

window.innerWidth 页面的宽

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
40
41
42
43
44
45
46
47
48
49
50
51
// 1. 点击弹出登录框
var link = document.getElementById("link");
var login = document.getElementById("login")
link.onclick = function() {
var login = document.getElementById("login");
var bg = document.getElementById("bg");
}
// 2 拖拽
// 2.1 鼠标按下
var title = document.getElementById("title");
title.onmousedown = function(e) {
e = e || event;
// 计算鼠标在盒子中的坐标
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
}
// 2.2 鼠标移动

document.onmousemove = function(e) {
e = e || event;
// 计算盒子在页面上的坐标
var loginX = e.pageX - x;
var loginY = e.pageY - y;

// 控制盒子的移动范围
if(loginX < 0 ){
loginX = 0;
}
if(loginY < 21){
loginY = 21;
}
// 如何获取页面和盒子的大小
// 盒子的大小
// login.offsetWidth
// 页面的大小? window.innerWidth
if(loginX > window.innerWidth - login.offsetWidth - 21){
loginX = window.innerWidth - login.offsetWidth -21;
}

if(loginY > window.innerHeight - login.offsetHeigh){
loginY = window.innerHeight - login.offsetHeight;
}

login.style.left = loginX + 256 + "px";
login.style.top = loginY - 140 + "px";
}

// 鼠标弹起,移除鼠标移动事件
document.onmouseup = function() {
document.onmousemove = null;
}
  1. 放大镜

onmouseover和onmouseout 会有事件冒泡
onmouseenter和onmouseleave 不会触发冒泡

1
2
3
4
5
6
7
8
9
<div class="box" id="box">
<div class="small">
<img src="images/small.jpg" width="350" alt=""/>
<div class="mask"></div>
</div>
<div class="big">
<img src="images/big.jpg" width="800" alt=""/>
</div>
</div>
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 0 获取所需要操作的元素

var box = document.getElementById("box");

// 小盒子
var smallBox = box.children[0];
// 大盒子
var bigBox = box.children[1];
// 小照片
var smallImg = smallBox.children[0];
// 遮罩层
var mask = smallBox.children[1];
// 大图片
var bigImg = bigBox.children[0];

// 1 鼠标移动到小盒子上 显示遮盖的层 显示大图

smallBox.onmouseover = function() {
mask.style.display = "block";
bigBox.style.display = "block";
}

smallBox.onmouseout = function() {
mask.style.display = "none";
bigBox.style.display = "none";
}

// 2 鼠标在小盒子中移动的时候,遮盖层跟着鼠标移动

smallBox.onmousemove = function() {
e= e||event;
// 获取鼠标在小盒子中的坐标
var x = getPage(e).pageX - box.offsetLeft;
var y = getPage(e).pageY - box.offsetTop;

// 让鼠标到mask中点
x -= mask.offsetWidth/2;
y -+ mask.offsetHeight/2;

// 控制x和y范围
x = x < 0 ? 0 : x;
y = y < 0 ? 0 : y;

var maxX = smallBox.offsetWidth - mask.offsetWidth;
var maxY = smallBox.offsetHeight - mask.offsetHeight;
x = x > maxX ? maxX : x;
y = y > maxY ? maxY : y;

mask.style.left = x + "px";
mask.style.top = y + "px";

// 3 显示对应的大图部分

// 计算大图的偏移量
// mask移动的距离/大图移动的距离 = mask最大能够移动的距离/大图片最大能移动的距离
// 大图片移动的距离 = mask移动的距离 * 大图片最大能够移动的距离 / mask最大能够移动的距离

// 大图片能够移动的最大距离

var bigMaxX = bigImg.offsetWidth - bigBox.offsetWidth;
var bigMaxY = bigImg.offsetWidth - bigBox.offsetHeight;

var bigImgX = x * bigMaxX/maxX;
var bigImgY = y * bigMaxY/maxY;

bigImg.style.left = -bigImgX + "px";
bigImg.style.top = -bigImgY + "px";
}
  1. 模拟滚动条
1
2
3
4
5
6
7
8
<div class="box" id="box">
<div class="content" id="content">
这里写文本信息
</div>
<div class="scroll" id="scroll">
<div class="bar" id="bar"></div>
</div>
</div>
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
40
41
42
43
44
45
46
47
48
49
50
// 0 获取元素
var box = document.getElementById("box");
var content = document.getElementById("content");
var scroll = document.getElementById("scroll");
var bar = document.getElementById("bar");

// 1 根据内容大小计算滚动条

// box的高度/content的高度 = bar的高度/scroll的高度
// 整个内容的大小
var barHeight = 0;
if(content.scrollHeight > box.offsetHeight){
barHeight = box.offsetHeight / content.scrollHeight * scroll.offsetHeight;
}
bar.style.height = barHeight + "px";
// 2. 拖动滚动条
// 2.1 鼠标在bar上按下的时候,计算鼠标在bar中的位置
bar.onmousedown = function(e) {
e = e || event;
// 鼠标在bar中的位置
var barY = getPage(e).pageY - bar.offsetTop - box.offsetTop;

// 2.2 鼠标在页面中移动的时候,计算bar在父容器中的坐标
document.onmousemove = function(e) {
e= e || event;
// bar在父容器中的位置
var y = getPage(e).pageY - barY - box.offsetTop;

// 限制y不能越界
y = y < 0 ? 0 : y;
// bar最大能移动的距离
var barMaxY = scroll.offsetHeight - barHeight;
y = y > barMaxY ? barMaxY : y;

bar.style.top = y + "px";

// 3. 当滚动条滚动的时候,移动内容
// bar移动的距离 / 内容移动的距离 = bar最大移动的距离 / 内容最大移动的距离
// 内容移动的距离 = bar移动的距离 * 内容最大移动的距离 / bar最大移动的距离
// 内容最大移动的距离
var contentMaxY = content.scrollHeight - box.offsetHeight;
var contentY = contentMaxY / barMaxY;
content.style.top = - contentY + "px";
}
}

// 当鼠标弹起的时候,移除移动的事件
document.onmouseup = function() {
document.onmousemove = null;
}

3.12 动画

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
40
41
42
43
44
45
46
47
48
49
var btn = document.getElementById("btn");
// 只生成一个div执行动画的定时器
var timerId = null;
btn.onclick = function() {
var box = document.getElementById("box");
var box1 = document.getElementById("box1");
animate(box,function() {
animate(box1);
});
// animate(box1);
}

// 封装函数 只生成一个div执行动画的定时器(把定时器放到element中)
function animate(element,callback) {

// 判断之前是否开启了定时器
if(element.timerId){
clearInterval(element.timerId);
}
// 让每一个执行动画的元素,记录自己的定时器
element.timerId = setInterval(function() {
// 目标位置
var target = 1000;
// 当前坐标
var current = element.offsetLeft;
// 进步
var step = 10;

// 当当前位置>目标位置step应该是负数
if(current > target){
step = - Math.abs(step);
}

// 编码要避免硬编码
// if(current >= 500)
// 如果当前位置和目标位置的差小鱼step,就认为到达目标位置
if(Math.abs(current - target) <= Math.abs(step)){
element.style.left = target + "px";
clearInterval(element.timerId);
return;
}
// 回调函数
if(callback){
callback()
}
current += step;
element.style.left = current + "px";
},20);
}

最后更新: 2019年01月20日 18:53

原始链接: http://linjiad.github.io/2019/01/14/WebApi2/

× 请我吃糖~
打赏二维码