笔记目录
小概
本章的学习内容大致有:定时器介绍及应用场景,offset家族介绍,实现匀速动画的封装。
1. 定时器的介绍
1.1 setInterval定时器(永久定时器)
1.定时器作用 : 一段代码 间隔时间 反复执行
2.定时器语法 :
开启定时器:
let timeID = setInterval(一段代码,间隔时间);
关闭定时器
clearInterval(timeID);
3.定时器注意点 :
setInterval()永久定时器 : 一但开启,间隔时间永久重复执行。只能手动清除。
- 应用场景:倒计时秒杀
<style>
span{
display: inline-block;
width: 50px;
height: 50px;
text-align: center;
line-height: 50px;
font-size: 20px;
background-color: #000;
color: #fff;
}
</style>
</head>
<body>
<span id="hour">01</span> :
<span id="minute">22</span> :
<span id="second">15</span>
<script>
/*需求分析
开启定时器,间隔1s
1.获取页面元素文本innerText : h,m,s
2.s--
3.如果s < 0,s = 59,m--
4.如果m < 0,m = 59,h--
5.如果h,m,s 小于10,则在前面加上0
6.将计算好的h,m,s重新赋值给innerText(重新渲染DOM树)
7.如果h,m,s 都为0,此时清除定时器
*/
let timeID = setInterval(function(){
//1.获取页面元素文本innerText : h,m,s
/* 注意点: innerText获取的内容是string类型,为了方便数学计算最好转成number类型 */
let h = +document.querySelector('#hour').innerText;
let m = +document.querySelector('#minute').innerText;
let s = +document.querySelector('#second').innerText;
//2.s--
s--;
//3.如果s < 0,s = 59,m--
if( s < 0){
s = 59;
m--;
};
//4.如果m < 0,m = 59,h--
if( m < 0 ){
m = 59;
h--;
};
//5.如果h,m,s 小于10,则在前面加上0
h = h < 10 ? '0' + h : h;
m = m < 10 ? '0' + m : m;
s = s < 10 ? '0' + s : s;
//6.将计算好的h,m,s重新赋值给innerText(重新渲染DOM树)
document.querySelector('#hour').innerText = h;
document.querySelector('#minute').innerText = m;
document.querySelector('#second').innerText = s;
//7.如果h,m,s 都为0,此时清除定时器
if( h == 0 && m == 0 && s == 0){
clearInterval(timeID);
};
},1000);
</script>
1.2 setTimeout定时器(一次定时器)
- 语法与setInterval一致,区别是,setTimeout定时器开启后间隔时间只能执行一次,而setInterval定时器如果不关闭可以一直执行
let pp = document.querySelector('#pp');
let timeID = null;
//开启
document.querySelector('#btn1').onclick = function(){
/**
* @description: 开启定时器
* @param {function} 一段代码(回调函数)
* @param {number} 间隔时间 单位:毫秒ms
* @return: timeID 定时器编号
*/
timeID = setTimeout(function(){
pp.innerText++;
},5000);
};
//关闭
document.querySelector('#btn2').onclick = function(){
/**
* @description:关闭定时器
* @param {number} 定时器ID
* 每开启一个定时器,编译器就会给这个定时器一个编号(用于区分不同定时器),称之为定时器id
* @return:
*/
clearTimeout(timeID);
};
2. offset属性介绍
offset家族:获取元素自身’真实’宽高与位置
- offsetwideth / offsetHeight :获取元素真实宽高 = content + padding + border
- offsetParent:获取元素最近的父级定位
2.1 如果一个元素是固定定位fixed,则定位父级是null
2.2 如果一个元素是非固定定位(absolute,relative,static),且所有的父级元素都没有定位,则定位父级是body
2.3 body的定位父级 是 null- offsetLeft / offsetTop: 获取子元素 左/上 内边框 到 定位父级 左/上 外边框距离
注意
获取:不仅可以获取行内属性,也可获取行外属性(点语法则不能获取行外属性)。
数据类型:number类型,不带单位(点语法返回值是string类型,带单位)。
设置:只能获取,不能设置(点语法可以设置任何属性)。
<style>
.one{
top:50px;
left: 50px;
width: 100px;
height: 100px;
background: greenyellow;
border: 10px solid red;
margin: 20px; /*offsetLeft/offsetTop=50+20 px */
position: absolute;
}
.two{
top: 200px;
left: 200px;
width: 200px;
height: 200px;
background: cyan;
border: 20px solid purple;
padding: 10px;
position: absolute;
}
</style>
</head>
<body>
<div class="two">
<div class="one" id="box">1</div>
</div>
<script>
let box = document.querySelector('#box');
//真实位置 = left/top + margin
console.log( box.offsetLeft,box.offsetTop );//70 70
//offsetParent
console.log( box.offsetParent ); //class:two
console.log( document.body.offsetParent );//null
</script>
3. 动画
3.1 动画介绍
- 原理:利用永久定时器给带定位的元素的left值 累加,letf值满足位置后用clearInterval()清除定时器、
/*
1.动画原理 :速度 距离/时间 m/s px/ms
* 元素移动原理: 有速度 单位时间ms 移动 单位距离px
2.动画核心思路
开启定时器,让元素单位时间移动单位距离
*/
let box = document.querySelector('.box');
let currentLeft = 0;
let timeID = null;
//移动400
document.querySelector('#btn1').onclick = function(){
//1.开始动画
timeID = setInterval(function(){
//2.1 开始移动
currentLeft += 18;
console.log( currentLeft );
box.style.left = currentLeft + 'px';
//2.2 边界检测 : 超过边界则停止移动
if( currentLeft >= 400 ){
//停止移动
clearInterval(timeID);
//元素复位 : 每一次移动的距离 和 目标位置不一定能整除,所以会产生误差
box.style.left = '400px';
};
},20);
};
</script>
3.2 匀速动画封装(移动距离不限)
匀速动画封装思路
1.解决动画代码冗余 -> 函数
2.解决距离不限 -> 参数
3.解决元素不限 -> 参数
4.解决方向不限
<style>
.box{
width: 200px;
height: 200px;
background-color: red;
position: absolute;
left: 88px;
}
</style>
</head>
<body>
<button id="btn1">移动到400</button>
<button id="btn2">移动到800</button>
<div class="box"></div>
<script>
let box = document.querySelector('.box');
//移动400
document.querySelector('#btn1').onclick = function(){
animationMove(400);
};
//移动800
document.querySelector('#btn2').onclick = function(){
animationMove(800);
};
let timeID = null;
function animationMove(target){
//1.开始动画之前先清除之前的定时器,以本次移动为准
clearInterval(timeID);
//2.开始本次动画
timeID = setInterval(function(){
//2.1 获取元素当前位置
let currentLeft = box.offsetLeft;
//2.2 开始移动
currentLeft += 10;
box.style.left = currentLeft + 'px';
//2.3 边界检测
if( currentLeft >= target ){
//停止动画
clearInterval(timeID);
//元素复位
box.style.left = target + 'px';
};
},20);
};
</script>
遇到的问题:如果连续触发定时器(快速点击btn),会使动画平移速度变快
解决方法:在函数内部,定时器开始前,先清除之前的定时器clearInterval(timeID);
3.3 匀速动画封装(移动元素不限)
<style>
.box{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 88px;
}
.box1{
width: 100px;
height: 100px;
background-color: green;
position: absolute;
left: 0px;
top: 150px;
}
</style>
</head>
<body>
<button id="btn1">移动到400</button>
<button id="btn2">移动到800</button>
<div class="box"></div>
<div class="box1"></div>
<script>
let box = document.querySelector('.box');
let box1 = document.querySelector('.box1');
//红色移动400
document.querySelector('#btn1').onclick = function(){
animationMove(400,box);
};
//绿色移动800
document.querySelector('#btn2').onclick = function(){
animationMove(800,box1);
};
/**
* @description:匀速动画
* @param {number}target : 目标位置
* @param {dom}ele : 目标元素
* @return:
*/
function animationMove(target,ele){
//1.开始动画之前先清除之前的定时器,以本次移动为准
clearInterval(ele.timeID);
//2.开始本次动画
/*
问题: 多个元素无法同时移动
分析: 多个元素移动,需要多个定时器同时工作。 而timeID变量一次只能存储一个定时器
解决: 存储多个定时器(每一个元素都需要一个存储定时器)
数组 : 存储多个数据,但是阅读性不高
对象: 存储多个数据,阅读性高(自定义属性存储定时器id)
*/
ele.timeID = setInterval(function(){
//2.1 获取元素当前位置
let currentLeft = ele.offsetLeft;
//2.2 开始移动
currentLeft += 10;
ele.style.left = currentLeft + 'px';
//2.3 边界检测
if( currentLeft >= target ){
//停止动画
clearInterval(ele.timeID);
//元素复位
ele.style.left = target + 'px';
};
},20);
};
遇到的问题:因为每次调用函数都会清除之前的定时器,每次只能执行一个定时器,无法同时使用。
解决方法:通过对象的自定义属性存储定时器id,ele.timeID = setInterval(function(){});clearInterval(ele.timeID)、
3.4 匀速动画封装(移动方向不限)
function animationMove(target, ele) {
//1.开始动画之前先清除之前的定时器,以本次移动为准
clearInterval(ele.timeID);
//2.开始本次动画
ele.timeID = setInterval(function () {
//2.1 获取元素当前位置
let currentLeft = ele.offsetLeft;
/* 使用布尔类型存储移动方向 true:从左往右 false:从右往左*/
let isLeft = target >= currentLeft ? true : false;
//2.2 开始移动
isLeft ? currentLeft += 10 : currentLeft -= 10;
ele.style.left = currentLeft + 'px';
//2.3 边界检测
if (isLeft ? currentLeft >= target : currentLeft <= target) {
//停止动画
clearInterval(ele.timeID);
//元素复位
ele.style.left = target + 'px';
};
}, 20);
};
判断移动的方向:元素当前位置>left值(target距离)则平移方向向左,自身offsetLeft递减到left值;元素当前位置<left值(target距离),则向右平移,自身offsetLeft递增到left值。
总结
匀速动画封装中判断方向稍微复杂一些,红色字体是我自身的一些理解,如果有表述不对的,希望有大佬及时指点、