动画
1. 动画实现原理
- 通过定时器setInterval()不断移动盒子的位置
- 实现步骤:
- 获得盒子当前位置
- 让盒子在当前位置上加上移动距离
- 利用定时器不断重复这个操作
- 加上结束定时器的条件 clearInterval();
- ⚠️元素需添加定位,才能使用element.style.left
<div></div> var div = document.querySelector('div'); var time = setInterval(function(){ if(div.offsetLeft >= 200){ // 移动200像素后停止 clearInterval(time) }else { div.style.left = div.offsetLeft + 10 + 'px'; } },1000) // 每秒移动10px
2. 动画函数封装
封装动画需传递2个参数(动画对象,移动到的距离)
function animate(obj,target){ clearInterval(obj.time); // 先清除定时器,在添加新的定时,这样使用按钮点击添加动画不会有bug obj.time = setInterval(function(){ // 这里不设置变量,使用对象添加,不同元素添加不同的定时器 if(obj.offsetLeft >= target){ // 移动200像素后停止 clearInterval(obj.time) }else { obj.style.left = obj.offsetLeft + 10 + 'px'; } },1000) } animate(div,300);
3. 缓动动画
缓动动画就是让元素运动速度有所变化,常见于让速度慢慢停下
实现步骤:
- 让元素每次移动的距离变小,速度就会慢慢落下
- 步长值的核心算法:(目标值-现在的位置)/10(可自定) 做为每次一定的距离步长
- 停止条件:让盒子当前位置等于目标位置就停止定时器
function animate(obj,target){ clearInterval(obj.time); obj.time = setInterval(function(){ var step = (target - obj.offsetLeft) / 10; // 步长值需写在定时器内 step = step > 0 ? Math.ceil(step) : Math.floor(step); // 判断步长是整数还是负数,整数往大取整,负数往小取整 if(obj.offsetLeft = target){ clearInterval(obj.time) }else { obj.style.left = obj.offsetLeft + step + 'px'; } },1000) }
4. 动画添加回调函数
在动画结束后在执行函数
function animate(obj,target,callBack){ clearInterval(obj.time); obj.time = setInterval(function(){ var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if(obj.offsetLeft = target){ clearInterval(obj.time); if(callBack){ // 回调函数写在定时器结束后面,用if判断是否有回调函数 callBack(); } }else { obj.style.left = obj.offsetLeft + step + 'px'; } },1000) } animate(div,300,function(){ alert('IU'); // 在动画结束时弹窗IU })
5. 动画函数封装调用
❤️案例:侧边栏滑动显示
var box = document.querySelector('.box');
var con = document.querySelector('.con');
var span = document.querySelector('span')
box.addEventListener('mouseenter', function () { // 鼠标经过
animate(con, -con.offsetWidth + box.offsetWidth, function () {
span.innerHTML = '➡️';
});
})
box.addEventListener('mouseleave', function () { // 鼠标离开
animate(con, 0, function () {
span.innerHTML = '⬅️';
})
})
❤️轮播图案例
<div class="box">
<ul class="banner">
<li>
<img src="./第六天/code/05-轮播图制作/upload/focus.jpg" alt="">
</li>
<li>
<img src="./第六天/code/05-轮播图制作/upload/focus1.jpg" alt="">
</li>
<li>
<img src="./第六天/code/05-轮播图制作/upload/focus2.jpg" alt="">
</li>
<li>
<img src="./第六天/code/05-轮播图制作/upload/focus3.jpg" alt="">
</li>
</ul>
<ul class="circle"></ul>
<span class="right"> > </span>
<span class="left"> < </span>
</div>
<script>
var box = document.querySelector('.box');
var circle = document.querySelector('.circle');
var banner = document.querySelector('.banner');
var left = document.querySelector('.left')
var right = document.querySelector('.right')
var boxWidth = box.offsetWidth; // 获取图片宽度
// 鼠标经过/离开,显示隐藏左右按钮
box.addEventListener('mouseenter', function () {
right.style.display = 'block';
left.style.display = 'block';
clearInterval(time); //鼠标经过停止定时器
time = null; // 清除定时器
})
box.addEventListener('mouseleave', function () {
right.style.display = 'none';
left.style.display = 'none';
time = setInterval(function () { // 鼠标离开重新打开定时器
right.click();
}, 2000)
})
// 利用for循环动态创建小圆点(有多少图创建多少个)
for (var i = 0; i < banner.children.length; i++) {
var li = document.createElement('li');
// 设置小圆点li的索引号(新增data-index属性)
li.setAttribute('data-index', i);
circle.appendChild(li);
// 生成小圆圈的同时绑定点击事件,利用排他思想
li.addEventListener('click', function () {
for (var i = 0; i < circle.children.length; i++) {
circle.children[i].className = '';
}
this.className = 'current';
// 点击小圆点移动图片
var index = this.getAttribute('data-index'); // 获取小圆点的index值
num = index; // 点击小圆点后把index值给num,避免再点击左右切换时出现bug
cir = index; // 点击小圆点后把index值给cir,避免再点击左右切换时出现bug
var imgs = - index * boxWidth; // 小圆点的index值*图片的宽度,就是需要移动的距离(负值)
clearInterval(banner.time);
// 动画函数
banner.time = setInterval(function () {
var step = (imgs - banner.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (banner.offsetLeft == imgs) {
clearInterval(banner.time);
}
banner.style.left = banner.offsetLeft + step + 'px';
}, 35)
})
}
circle.children[0].className = 'current';
// 克隆第一张图放在最后形成无缝衔接
var first = banner.children[0].cloneNode(true);
banner.appendChild(first);
// 左右按钮点击图片切换
var num = 0; // 控制图片
var cir = 0; // 控制小圆点
left.addEventListener('click', function () {
if (num == 0) {
num = banner.children.length - 1;
banner.style.left = - num * boxWidth + 'px';
}
num--;
var imgs = - num * boxWidth;
clearInterval(banner.time);
banner.time = setInterval(function () {
var step = (imgs - banner.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (banner.offsetLeft == imgs) {
clearInterval(banner.time);
}
banner.style.left = banner.offsetLeft + step + 'px';
}, 35)
// 小圆点跟随图片显示
cir--;
if (cir < 0) {
cir = circle.children.length - 1;
}
for (var i = 0; i < circle.children.length; i++) {
circle.children[i].className = '';
}
circle.children[cir].className = 'current';
});
right.addEventListener('click', function () {
if (num == banner.children.length -1){
banner.style.left = '0';
num = 0;
}
num++;
var imgs = - num * boxWidth;
clearInterval(banner.time);
banner.time = setInterval(function () {
var step = (imgs - banner.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (banner.offsetLeft == imgs) {
clearInterval(banner.time);
}
banner.style.left = banner.offsetLeft + step + 'px';
}, 35)
// 小圆点跟随图片显示
cir++;
if(cir == circle.children.length){
cir =0;
}
for(var i =0;i<circle.children.length;i++){
circle.children[i].className = '';
}
circle.children[cir].className = 'current';
});
// 自动播放
var time = setInterval(function(){
right.click(); // 手动调用右侧点击事件
},2000)
</script>
6. 节流阀
- 节流阀:防止轮播图按钮连续点击造成播放过快
- 目的:上一个动画执行完毕后再执行下一个动画,让事件无法连续触发
- 实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
- 设置一个变量:var flag = true;
- if(flag){flag=flase;do sometiing} 关闭节流阀
- 利用回调函数,动画执行完毕 flag=true 打开节流阀
❤️案例:跟随鼠标移动背景图位置
<div>
<span></span>
<ul>
<li>首页</li>
<li>动画</li>
<li>活动</li>
<li>文化</li>
<li>简介</li>
<li>信息</li>
</ul>
</div>
var span = document.querySelector('span');
var ul = document.querySelector('ul');
var num = 0; // 背景图起始位置
for(var i = 0;i<ul.children.length;i++){
ul.children[i].addEventListener('mouseenter',function(){
animate(span, this.offsetLeft)
})
ul.children[i].addEventListener('mouseleave',function(){
animate(span,num) // 离开还原起始位置
})
ul.children[i].addEventListener('click',function(){
num = this.offsetLeft; // 点击后重新计算起始位置
for(var i = 0 ;i <ul.children.length;i++){
ul.children[i].style.color = '';
}
this.style.color = 'red';
})
}
7. 返回顶部动画
function animate(obj,target,callBack){
clearInterval(obj.time);
obj.time = setInterval(function(){
var tep = (target - window.pageYOffset) / 10;
tep = tep > 0? Math.ceil(tep) : Math.floor(tep);
if(window.pageYoffset == target){
clearInterval(obj.time)
callBack && callBack();
}else {
window.scroll(0,tep + window.pageYOffset)
}
},50)
}
animate(window,0);