-BOM
BOM概述
window对象常见事件
窗口加载事件
window.onload
页面加载事件
window.onload 是窗口(页面加载事件),当文档内容完全加载完成会触发该事件(包括图像、脚本文件、css文件等),就调用处理函数。
1.有了window.onload就可以把js代码写到元素页面的上方,因为onload是等页面内容全部加载完毕再去执行处理函数。
2.window.onload 传统注册事件只能写一次,如多有多个就会以最后一个window.onload为准。
3.如果使用addEventListener则没有限制。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//---------传统注册事件--------------------------------
// window.onload = function (){
// var btn = document.querySelector('button');
// btn.addEventListener('click',function(){
// alert('123')
// })
// }
// window.onload = function(){
// alert(22)
// }
// --------------如果使用addEventListener则没有限制。------------------------
// 推荐
window.addEventListener('load', function () {
var btn = document.querySelector('button');
btn.addEventListener('click', function () {
alert('123')
})
})
window.addEventListener('load', function () {
alert(22)
})
</script>
<button>点击</button>
</body>
</html>
DOMContentLoaded
DOMContentLoaded 事件触发时候,仅当DOM加载完成,不包括样式表、图片、flash等。ie9以上支持。
如果页面图片很多的话,从用户访问到onload触发可能需要较长的时间交互效果就不能实现,必然影响用户体验,此时用DOMContentLoaded 事件比较合适。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// --------------如果使用addEventListener则没有限制。------------------------
// 推荐
window.addEventListener('load', function () {
var btn = document.querySelector('button');
btn.addEventListener('click', function () {
alert('123')
})
})
window.addEventListener('load', function () {
alert(22)
})
// -------DOMContentLoaded -----------------
documen.addEventListener('DOMContentLoaded', function () {
alert(33);
})
</script>
<button>点击</button>
</body>
</html>
比较
load是等页面内容全部加载完毕,包含dom元素 图片 flash css 等
DOMContentLoaded 是DOM加载完毕,不包含图片 flash css 等就可以执行 加载速度比load跟快一些。
调整窗口大小事件
window.onresize = function(){};
window.addEventListener('resize',function(){
})
window.onresize 是调整窗口大小加载事件,当触发时候就调用的处理函数
注意:
只要窗口大小发生改变,就会触发这个事件。
我们职场利用这个事件来完成响应式布局。window.innerWidth 当前屏幕的宽度。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: cornflowerblue;
}
</style>
</head>
<body>
<div></div>
<script>
var div = window.document.querySelector('div');
window.addEventListener('resize', function () {
console.log('变化了');
console.log(window.innerWidth);
if (window.innerWidth <= 800) {
div.style.display = 'none';
}
else {
div.style.display = 'block';
}
})
</script>
</body>
</html>
定时器
window对象提供了两种定时器
- setTimeout()
- setInterval()
setTimeout() 定时器
只调用一次!!!
setTimeout() 方法用于设置一个定时器,该定时器到期后执行调用函数。
setTimeout() 这个函数我们也称为回调函数callback
普通函数是按照代码顺序直接调用。 而这个函数,需要等待时间,时间到了才调用这个函数。
element.onclick = function(){} 或者element.addEventListener(){‘click’,funcion(){}}; 里面的函数也是回调函数。
window.setTimeout(调用函数,[延迟毫秒数]);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- -->
<script>
// 这个window在调用时候可以shenglue
// 这个延迟时间默认是毫秒,但是可以省略,如果省略默认是0
//第一种写法
setTimeout(function () {
alert('已经两秒了')
}, 2000)
//第二种写法
// 这个调用函数可以直接写函数 还可以 写函数名
function boom() {
alert('砰!')
}
setTimeout(boom, 3000)
// 还有一种写法 不提倡
setTimeout('boom()', 4000)
// 页面中可能有很多定时器,所以 最好给定时器加标识符(名字)
var timer1 = setTimeout(boom, 5000)
</script>
</body>
</html>
自动关闭广告案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 200px;
height: 600px;
background-color: coral;
}
</style>
</head>
<body>
<div>
这是广告
</div>
<script>
var ad = document.querySelector('div');
setTimeout(function () {
ad.style.display = 'none';
}, 3000)
</script>
</body>
</html>
清除定时器clearTimeout
停止setTimeout() 定时器
window.clearTimeout(timeoutID)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>停止定时器</button>
<script>
var btn = document.querySelector('button');
var timer = setTimeout(function () {
console.log('砰')
}, 3000)
btn.addEventListener('click', function () {
clearTimeout(timer)
})
</script>
</body>
</html>
setInterval()定时器
可以一直循环调用!!!
window.setInterval(回调函数,[间隔的毫秒数]);
setInterval() 方法重复调用一个函数,每隔这个事件就去调用一次回调函数。
注意:
- window可以省略。
- 这个回调函数可以直接写函数,或者写函数名或者采取字符串’函数名’ 三种形式。
- 间隔毫秒数默认是0,如果写,必须是毫秒,标书每隔多少毫秒就自动调用这个函数。
- 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
setInterval(function(){
console.log('砰!');
},1000)
</script>
</body>
</html>
小米倒计时案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box {
width: 150px;
height: 200px;
border: 1px #ccc solid;
margin: 100px auto;
}
#box>div {
/* border: 1px #ccc solid; */
margin-top: 120px;
width: 150px;
height: 40px;
}
span {
display: inline-block;
height: 40px;
width: 40px;
background-color: #32332E;
margin-left: 5px;
text-align: center;
line-height: 40px;
color: cornsilk;
}
</style>
</head>
<body>
<div id="box">
<div>
<span class="hour">1</span>
<span class="minute">2</span>
<span class="second">3</span>
</div>
</div>
<script>
// 1.获取元素
// 时分秒的三个小盒子
var hour = document.querySelector('.hour');
var minute = document.querySelector('.minute');
var second = document.querySelector('.second');
var inputTime = +new Date('2020-9-1 00:00:00');//返回用户输入时间的毫秒数
// 先调用一次倒计时函数,防止页面刷新有空白
conutDown()
// 开启定时器
setInterval(conutDown, 1000)
function conutDown() {
var nowTime = +new Date();//返回当前时间的毫秒数
var times = (inputTime - nowTime) / 1000; //times就是剩余时间总的秒数
var h = parseInt(times / 60 / 60 % 24);//计算小时
h = h < 10 ? '0' + h : h;
// 把剩余时间赋值给盒子 下面同理
hour.innerHTML = h;
var m = parseInt(times / 60 % 60);//计算分钟
m = m < 10 ? '0' + m : m;
minute.innerHTML = m;
var s = parseInt(times % 60);//计算秒数
s = s < 10 ? '0' + s : s;
second.innerHTML = s;
}
</script>
</body>
</html>
清除定时器clearInterval
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button class="begin">开始定时器</button>
<button class="stop">停止定时器</button>
<script>
var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
// 先定义一个全部变量方便下面使用 null是一个空对象
var timer = null;
begin.addEventListener('click', function () {
timer = setInterval(function () {
console.log('定时器开始工作');
}, 1000)
})
stop.addEventListener('click', function () {
clearInterval(timer);
})
</script>
</body>
</html>
发送短信案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="number">
<button>点击发送短信</button>
<script>
var input = document.querySelector('input');
var btn = document.querySelector('button');
var time = 5;
btn.addEventListener('click', function () {
btn.disabled = true;
var timer = setInterval(function () {
if (time == 0) {
// 清除定时器
clearInterval(timer);
btn.innerHTML = '点击输入短信'
btn.disabled = false;
// 清除定时器之后要重新给time赋值
time = 5;
}
else {
btn.innerHTML = '还剩下' + time + '秒'
time = time - 1;
}
}, 1000)
})
</script>
</body>
</html>
js的执行队列
javaScript 最大的特点就是单线程,同一个事件只能做一件事情。
单线程意味着任务需要排队,会导致的问题:如果js执行时间过长,这样会造成渲染不连贯,导致加载阻塞的感觉。
同步和异步
js的执行机制
location对象
window 对象给我们提供了一个location属性 用于获取或设置窗体的URL,并且可以用于解析URL。因为这个属性返回的是一个对象,所以我们将这个属性也称为location对象
URL
统一资源定位符(url),是互联网上标准资源的地址。互联网上每个文件都有一个位置的url,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
location对象的属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
// console.log(window.location.href);
// 点击页面跳转
location.href = 'https://www.bilibili.com/'
})
</script>
</body>
</html>
5秒页面跳转案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>点击</button>
<div></div>
<script>
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.addEventListener('click', function () {
// console.log(window.location.href);
// 点击页面跳转
location.href = 'https://www.bilibili.com/'
})
var time = 5;
//先在前面调用一次函数就不会有一秒的空白
conutDown();
setInterval(conutDown, 1000)
function conutDown() {
if (time == 0) {
location.href = 'https://www.bilibili.com/'
time = 5;
} else {
div.innerHTML = '在' + time + '秒后跳转到雄的页面'
time--
}
}
</script>
</body>
</html>
获取URL参数,数据在不同页面传递
https://www.bilibili.com/video/BV1k4411w7sV?p=93
login界面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="index.html">
用户名:<input type="text" name="uname">
<input type="submit" value="登陆">
</form>
</body>
</html>
index界面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div></div>
<script>
console.log(location.search);// ?uname=1750306016
// 1.去掉? 用 substr('截取的起始位置','截取几个字符')
var params = location.search.substr(1);
console.log(params);
// 2.利用 = 号 把字符串分割为数组 split('=')
// 字符替换为数组 split('分隔符') 与join()把数组转化为字符串相反
// split('分隔符') 里面的分隔符取决于 字符串 里面用什么符号隔开
var arr = params.split('=');
console.log(arr);
// 把数据写入div中
var div = document.querySelector('div');
div.innerHTML = arr[1]+'你好';
</script>
</body>
</html>
location 对象的方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
// 可以记录浏览历史 所以可以实现后退功能
// location.assign('https://www.bilibili.com/');
// 不可以记录浏览历史 所以不可以实现后退功能
// location.replace('https://www.bilibili.com/');
// 刷新按钮
location.reload();
})
</script>
</body>
</html>
navigator对象
navigator 对象 包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。
下面的前端代码可以判断用户哪个终端打开页面:
代码演示视频
https://www.bilibili.com/video/BV1k4411w7sV?p=95
history 对象
window 对象 给我们提供了一个history 对象,与浏览器记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。
前进后退功能类似于下面按钮
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
history.forward();
})
PC端页面特效
元素偏移量offset系列
offset 翻译过来就是偏移量,我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
- 获得元素距离带有定位父元素的位置。
- 获得自身的大小(宽高)。
- 注意:返回的数值都不带单位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
margin: 0;
padding: 0;
}
.father {
/* 定位 */
position: relative;
width: 100px;
height: 100px;
background-color: coral;
margin: 100px;
}
.son {
width: 50px;
height: 50px;
background-color: cornflowerblue;
margin: 40px;
}
.w {
width: 200px;
height: 200px;
background-color: rgb(76, 223, 142);
margin: 0 auto 200px;
padding: 20px;
border: 2px solid #000;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
<div class="w"></div>
</div>
<script>
var father = document.querySelector('.father')
var son = document.querySelector('.son')
var w = document.querySelector('.w')
// 1.获得元素的偏移量 位置 返回不带单位的数值
console.log(father.offsetTop);
console.log(father.offsetLeft);
// 它以带有定位的父亲为准 如果没有父亲或者父亲没有定位 则以 body 为准
console.log(son.offsetLeft);
// 2.可以得到元素的大小 宽度 和高度 是包含 padding + border + width
console.log(w.offsetWidth);
console.log(w.offsetHeight);
// 3. 返回带有定位的父亲 否则返回的是body
console.log(son.offsetParent);
//返回父亲 返回的是最近一级的父亲 不管父亲有没有定位
console.log(son.parentNode);
</script>
</body>
</html>
offset与style的区别
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box{
width: 200px;
height: 200px;
background-color: rgb(85, 161, 228)
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var box = document.querySelector('.box');
console.log(box.offsetWidth);
console.log(box.style.width);
</script>
</body>
</html>
获取鼠标在盒子内的坐标案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 300px;
height: 300px;
background-color: burlywood;
margin: 100px auto;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
// 鼠标在页面的坐标(e.pageX,e.pageY)
// 盒子到页面的距离(box.offsetLeft,box.offsetTop)
var box = document.querySelector('.box')
box.addEventListener('mousemove', function (e) {
// console.log(e.pageX)
// console.log(e.pageY);
// console.log(box.offsetLeft);
// console.log(box.offsetTop);
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// console.log(x);
// console.log(y);
box.innerHTML = 'x的坐标是:'+x+'y的坐标是:'+y;
})
</script>
</body>
</html>
案例:模态框拖拽
有bug未解决 鼠标点击时候模态框会跳开
<style>
.con {
padding: 200px 0 0 200px;
}
.box {
width: 300px;
box-sizing: border-box;
position: relative;
}
.box img {
width: 100%;
}
.mask {
display: none;
position: absolute;
width: 100px;
height: 100px;
top: 0;
left: 0;
background-color: yellow;
opacity: .5;
cursor: move;
/* transform: translate(-50%, -50%); */
}
.big {
display: none;
width: 600px;
height: 600px;
position: absolute;
left: 550px;
top: 200px;
background-color: pink;
border: solid 2px black;
overflow: hidden;
z-index: 999;
}
.big img {
width: 1000px;
display: block;
position: absolute;
top: 0;
left: 0;
}
</style>
<div class="con">
<div class="box">
<img src="/js进阶BOM/案例/timg.jpg" alt="">
<!-- 遮挡层 -->
<div class="mask"></div>
</div>
<div class="big">
<img src="/js进阶BOM/案例/timg.jpg" alt="" class="bigimg">
</div>
</div>
<!--
案例分析:
1、整个案例可以分为三个功能模块
2、鼠标经过小图片盒子,黄色的遮挡层和大图片盒子显示,离开隐藏两个盒子功能
3、黄色的遮挡层跟随鼠标功能
4、移动黄色遮挡层,大图片跟随移动功能
5、获得鼠标在盒子的坐标
6、把数值给遮挡层作为left和top值
7、此时用到鼠标移动事件,但是还是在小图片盒子内移动
8、遮挡层不能超出雄安盒子范围
9、如果小于0,就把坐标设置为0q
10、求大图片的移动距离公式
遮挡层/遮挡层最大移动距离 = 大图片移动距离/大图片最大移动距离
-->
<script>
window.addEventListener('load', function () {
var box = document.querySelector('.box');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
// 鼠标经过box时 大盒子 big 和遮挡层 mask 显示
box.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
box.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
box.addEventListener('mousemove', function (e) {
// 先计算出鼠标在盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// 遮挡层mask距离盒子边框的距离 或者说mask 移动的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// 遮挡层最大移动距离
var maskMax = box.offsetWidth - mask.offsetWidth;
var maskMaxY = box.offsetHeight - mask.offsetHeight;
// 如果x坐标小于0,就让mask停在0的位置
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMax) {
maskX = maskMax;
}
// Y坐标
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMaxY) {
maskY = maskMaxY;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 大图
var bigimg = document.querySelector('.bigimg');
// 大图可移动距离等于图片 - (大盒)容器宽度
var bigmax = bigimg.offsetWidth - big.offsetWidth;
var bigmaxY = bigimg.offsetHeight - big.offsetHeight;
console.log(bigimg.offsetWidth);
console.log(bigmax);
// 大图的移动距离,根据公式: 遮挡层/遮挡层最大移动距离 = 大图片移动距离/大图片最大移动距离
var bigX = maskX * bigmax / maskMax;
var bigY = maskY * bigmaxY / maskMaxY;
bigimg.style.left = -bigX + 'px';
bigimg.style.top = -bigY + 'px';
})
})
</script>
案例:仿京东放大镜效果
<style>
.con {
padding: 200px 0 0 200px;
}
.box {
width: 300px;
box-sizing: border-box;
position: relative;
}
.box img {
width: 100%;
}
.mask {
display: none;
position: absolute;
width: 100px;
height: 100px;
top: 0;
left: 0;
background-color: yellow;
opacity: .5;
cursor: move;
/* transform: translate(-50%, -50%); */
}
.big {
display: none;
width: 600px;
height: 600px;
position: absolute;
left: 550px;
top: 200px;
background-color: pink;
border: solid 2px black;
overflow: hidden;
z-index: 999;
}
.big img {
width: 1000px;
display: block;
position: absolute;
top: 0;
left: 0;
}
</style>
<div class="con">
<div class="box">
<img src="/js进阶BOM/案例/timg.jpg" alt="">
<!-- 遮挡层 -->
<div class="mask"></div>
</div>
<div class="big">
<img src="/js进阶BOM/案例/timg.jpg" alt="" class="bigimg">
</div>
</div>
<!--
案例分析:
1、整个案例可以分为三个功能模块
2、鼠标经过小图片盒子,黄色的遮挡层和大图片盒子显示,离开隐藏两个盒子功能
3、黄色的遮挡层跟随鼠标功能
4、移动黄色遮挡层,大图片跟随移动功能
5、获得鼠标在盒子的坐标
6、把数值给遮挡层作为left和top值
7、此时用到鼠标移动事件,但是还是在小图片盒子内移动
8、遮挡层不能超出雄安盒子范围
9、如果小于0,就把坐标设置为0q
10、求大图片的移动距离公式
遮挡层/遮挡层最大移动距离 = 大图片移动距离/大图片最大移动距离
-->
<script>
window.addEventListener('load', function () {
var box = document.querySelector('.box');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
// 鼠标经过box时 大盒子 big 和遮挡层 mask 显示
box.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
box.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
box.addEventListener('mousemove', function (e) {
// 先计算出鼠标在盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// 遮挡层mask距离盒子边框的距离 或者说mask 移动的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// 遮挡层最大移动距离
var maskMax = box.offsetWidth - mask.offsetWidth;
var maskMaxY = box.offsetHeight - mask.offsetHeight;
// 如果x坐标小于0,就让mask停在0的位置
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMax) {
maskX = maskMax;
}
// Y坐标
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMaxY) {
maskY = maskMaxY;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 大图
var bigimg = document.querySelector('.bigimg');
// 大图可移动距离等于图片 - (大盒)容器宽度
var bigmax = bigimg.offsetWidth - big.offsetWidth;
var bigmaxY = bigimg.offsetHeight - big.offsetHeight;
console.log(bigimg.offsetWidth);
console.log(bigmax);
// 大图的移动距离,根据公式: 遮挡层/遮挡层最大移动距离 = 大图片移动距离/大图片最大移动距离
var bigX = maskX * bigmax / maskMax;
var bigY = maskY * bigmaxY / maskMaxY;
bigimg.style.left = -bigX + 'px';
bigimg.style.top = -bigY + 'px';
})
})
</script>
元素可视区client系列
我们使用client系列的相关属性来获取元素可视区的相关信息。通过client系列的相关属性可以得改元素的边框大小、元素大小等。
立即执行函数
(function(){})()
主要作用:创建一个独立作用域 避免命名冲突问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 立即执行函数:需要调用立马能够自己执行的函数。
// 两种写法
// (function(){})();
// // 或者
// (function(){}());
(function (a, b) {
console.log(a);
console.log(a + b);
console.log(2);
//第二个小括号可以看做是调用函数 里面可以添加实参
})(1, 3);
// 如果有多个立即执行函数中间一定要用分号隔开
// 也可以给函数添加名字
(function sum(a, b) {
console.log(a + b);
}(2, 3))
// 立即执行函数最大的作用就是 独立创造了一个作用域 里面所有的变量都是局部变量
</script>
</body>
</html>
元素滚动scroll系列
scroll系列的相关属性可以动态的得到该元素的大小滚动距离
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div{
width: 100px;
height: 100px;
background-color: brown;
overflow: auto;
}
</style>
</head>
<body>
<div>
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
</div>
<script>
var div = document.querySelector('div');
div.addEventListener('scroll',function(){
console.log(div.scrollLeft);
})
</script>
</body>
</html>
淘宝右侧侧边栏案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body,
html {
margin: 0;
padding: 0;
}
.header {
width: 95%;
height: 300px;
background-color: cadetblue;
margin: 0px auto
}
.article {
width: 95%;
height: 1000px;
background-color: rgb(80, 225, 230);
margin: 10px auto
}
.footer {
width: 95%;
height: 200px;
background-color: rgb(24, 137, 141);
margin: 10px auto
}
.aside {
position: absolute;
width: 40px;
height: 100px;
background-color: chartreuse;
right: 10px;
top: 310px;
}
.aside div {
width: 100%;
background-color: darkorange;
margin: 50px auto;
display: none;
cursor: pointer;
}
</style>
</head>
<body>
<div class="header">头部</div>
<div class="aside">
<div id="backtop">返回顶部</div>
</div>
<div class="article">正文</div>
<div class="footer">尾部</div>
<!--
案例分析
1.需要页面滚动元素 scroll 因为是页面滚动 所以事件源是document。
2.滚动到某个位置,就是判断页面被卷去的上部值
3.页面被卷去的头部,可以通过window.pageYOffset 获得 去过 被卷去的是左侧 window.pageXOffset
4.注意:元素被卷去的头部是element.scrollTop,如果是页面被卷去的头部则是window.pageYOffset
-->
<script>
// 获取元素
var aside = document.querySelector('.aside');
var backtop = document.querySelector('#backtop')
var header = document.querySelector('.header')
console.log(header);
// 头部的高度
console.log(header.offsetHeight);
// 页面滚动事件
document.addEventListener('scroll', function () {
// 页面被卷去的头部
console.log(window.pageYOffset);
// 3.当我们页面被卷去的头部大于300px 此时侧边栏改为固定定位
if (window.pageYOffset >= header.offsetHeight) {
aside.style.position = 'fixed'
aside.style.top = 0 + 'px'
backtop.style.display = 'block'
}
else {
aside.style.position = 'absolute'
aside.style.top = header.offsetHeight + 'px'
backtop.style.display = 'none'
}
})
backtop.addEventListener('click', function () {
window.pageYOffset = 0;
})
</script>
</body>
</html>
三大系列总结
他们的主要用法:
1.offset系列经常用于获取元素位置 offsetLeft offsetTop
2.client经常用于获取元素大小 clientWidth clientHight
3.scroll经常用于获取滚动距离 scrollTop scrollLeft
4.注意页面的滚动距离通过window.pageXOffset 获得
动画原理
核心原理:通过定时器()不断移动盒子位置。
实现步骤:
- 获得盒子当前的位置
- 让盒子在当前位加上1和移动距离
- 利用定时器不断重复这个动作
- 加一个结束定时器的条件。
- 注意元素需要添加定位,才能使用element.style.left
动画函数封装
注意函数需要传递的两个参数,动画对象和移动的距离。
动画函数给不同元素记录定时器
如果多个元素都使用这个动画效果,每次都要声明一个定时器,我们可以给不同的元素使用不同的定时器(自己专门使用自己的定时器)。
核心原理:利用js是一门动态语言,可以很方便的给当前对象添加属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: absolute;
left: 0;
width: 200px;
height: 200px;
background-color: blueviolet;
}
span {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: rgb(83, 155, 113);
}
button {
margin-top: 300px;
}
</style>
</head>
<body>
<div></div>
<span></span>
<button>点击方块移动</button>
<!--
动画原理
1. 获得盒子当前的位置
2. 让盒子在当前位加上1和移动距离
3. 利用定时器不断重复这个动作
4. 加一个结束定时器的条件。
5. 注意元素需要添加定位,才能使用element.style.left
-->
<script>
// 简单动画函数的封装 obj目标函数 target目标对象
function animate(obj, target) {
// 解决方案就是让元素只有一个定时器执行
// 先清除以前的定时器只保留一个定时器执行
clearInterval(obj.timer)
//↓↓↓↓↓ 给不同元素指定了不同的定时器
obj.timer = setInterval(function () {
if (obj.offsetLeft >= target) {
// 停止动画本质是停止定时器
clearInterval(obj.timer)
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 1)
}
var div = document.querySelector('div');
var span = document.querySelector('span')
// 调用函数
var button = document.querySelector('button');
// 当我们不断点击了按钮,这个元素的速度会越来越快,因为开启了太多的定时器
// 解决方案就是让元素只有一个定时器执行
button.addEventListener('click', function () {
animate(div, 200)
animate(span, 600)
})
</script>
</body>
</html>
缓动动画原理
缓动动画就是让元素的运动速度有所变化。
思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
- 核心算法:(目标值 - 现在的值)/ 10 作为每次移动距离步长
- 停止的条件是:让当前盒子位置等于目标位置就停止定时器
- 步长值需要取整
后退有点bug
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: absolute;
left: 0;
width: 200px;
height: 200px;
background-color: blueviolet;
}
span {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: rgb(83, 155, 113);
}
button {
margin-top: 300px;
}
</style>
</head>
<body>
<div></div>
<span></span>
<button class="button600">点击方块移动600</button>
<button class="button1000">点击方块移动1000</button>
<script>
// 简单动画函数的封装 obj目标函数 target目标对象
function animate(obj, target) {
// 解决方案就是让元素只有一个定时器执行
// 先清除以前的定时器只保留一个定时器执行
clearInterval(obj.timer)
//↓↓↓↓↓ 给不同元素指定了不同的定时器
obj.timer = setInterval(function () {
// 步长值写到定时器里面
// 把步长值改为整数不要出现小数的距离
// var step = Math.ceil((target - obj.offsetLeft) / 10);
// 判断div是前进还是后退 时候 步长值是向上取整还是向下取整
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step)
if (obj.offsetLeft >= target) {
// 停止动画本质是停止定时器
clearInterval(obj.timer)
}
//
obj.style.left = obj.offsetLeft + step + 'px';
}, 15)
}
var div = document.querySelector('div');
var span = document.querySelector('span')
// 调用函数
var btn600 = document.querySelector('.button600');
var btn1000 = document.querySelector('.button1000');
// 当我们不断点击了按钮,这个元素的速度会越来越快,因为开启了太多的定时器
// 解决方案就是让元素只有一个定时器执行
btn600.addEventListener('click', function () {
animate(div, 200)
})
btn1000.addEventListener('click', function () {
animate(div, 600)
})
</script>
</body>
</html>
动画函数添加回调函数
回调函数原理:函数可以作为一个参数。将这个函数作为一个参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调
回调函数写的位置:定时器结束的位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: absolute;
left: 0;
width: 200px;
height: 200px;
background-color: blueviolet;
}
button {
margin-top: 300px;
}
</style>
</head>
<body>
<div></div>
<button class="button600">点击方块移动600</button>
<button class="button1000">点击方块移动1000</button>
<script>
function animate(obj, target, callback) {
clearInterval(obj.timer)
obj.timer = setInterval(function () {
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step)
if (obj.offsetLeft >= target) {
// 停止动画本质是停止定时器
clearInterval(obj.timer)
// 回调函数写到定时器里面
if (callback) {
// 调用函数
callback();
}
}
//
obj.style.left = obj.offsetLeft + step + 'px';
}, 15)
}
var div = document.querySelector('div');
var span = document.querySelector('span')
// 调用函数
var btn600 = document.querySelector('.button600');
var btn1000 = document.querySelector('.button1000');
// 当我们不断点击了按钮,这个元素的速度会越来越快,因为开启了太多的定时器
// 解决方案就是让元素只有一个定时器执行
btn600.addEventListener('click', function () {
// 回调函数
animate(div, 200, function () {
div.style.backgroundColor = 'pink';
})
})
btn1000.addEventListener('click', function () {
animate(div, 600)
})
</script>
</body>
</html>
动画函数封装到单独js文件里面
独立新建一个js文件。
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: absolute;
left: 0;
width: 200px;
height: 200px;
background-color: blueviolet;
}
</style>
<script src="/js进阶BOM/js/animate.js"></script>
</head>
<body>
<div></div>
<script>
var div = document.querySelector('div');
div.addEventListener('click', function () {
animate(div, 400);
})
</script>
</body>
</html>
js文件
function animate(obj, target, callback) {
clearInterval(obj.timer)
obj.timer = setInterval(function () {
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step)
if (obj.offsetLeft >= target) {
// 停止动画本质是停止定时器
clearInterval(obj.timer)
// 回调函数写到定时器里面
if (callback) {
// 调用函数
callback();
}
}
//
obj.style.left = obj.offsetLeft + step + 'px';
}, 15)
}
mouseenter和mouseover的区别
mouseenter鼠标事件
- 当鼠标移动到元素上时就会触发mouseenter事件
- 类似于mouseover,他们两者之间的差别是
- mouseover 鼠标经过自身盒子会触发,经过子级盒子还会触发。mouseenter 只会经过自身盒子触发。
- 之所以这样是因为mouseenter不会冒泡。
- 跟mouseenter搭配的鼠标离开事件mouseleave同样不会冒泡
常见网页特效案例
div.style.backgroundColor = 'pink';
})
})
btn1000.addEventListener('click', function () {
animate(div, 600)
})
</script>
```
动画函数封装到单独js文件里面
独立新建一个js文件。
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: absolute;
left: 0;
width: 200px;
height: 200px;
background-color: blueviolet;
}
</style>
<script src="/js进阶BOM/js/animate.js"></script>
</head>
<body>
<div></div>
<script>
var div = document.querySelector('div');
div.addEventListener('click', function () {
animate(div, 400);
})
</script>
</body>
</html>
js文件
function animate(obj, target, callback) {
clearInterval(obj.timer)
obj.timer = setInterval(function () {
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step)
if (obj.offsetLeft >= target) {
// 停止动画本质是停止定时器
clearInterval(obj.timer)
// 回调函数写到定时器里面
if (callback) {
// 调用函数
callback();
}
}
//
obj.style.left = obj.offsetLeft + step + 'px';
}, 15)
}
mouseenter和mouseover的区别
mouseenter鼠标事件
- 当鼠标移动到元素上时就会触发mouseenter事件
- 类似于mouseover,他们两者之间的差别是
- mouseover 鼠标经过自身盒子会触发,经过子级盒子还会触发。mouseenter 只会经过自身盒子触发。
- 之所以这样是因为mouseenter不会冒泡。
- 跟mouseenter搭配的鼠标离开事件mouseleave同样不会冒泡