前端-JS进阶-动画

动画

1. 动画实现原理

  1. 通过定时器setInterval()不断移动盒子的位置
  2. 实现步骤:
    1. 获得盒子当前位置
    2. 让盒子在当前位置上加上移动距离
    3. 利用定时器不断重复这个操作
    4. 加上结束定时器的条件 clearInterval();
    5. ⚠️元素需添加定位,才能使用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. 缓动动画

  1. 缓动动画就是让元素运动速度有所变化,常见于让速度慢慢停下

  2. 实现步骤:

    1. 让元素每次移动的距离变小,速度就会慢慢落下
    2. 步长值的核心算法:(目标值-现在的位置)/10(可自定) 做为每次一定的距离步长
    3. 停止条件:让盒子当前位置等于目标位置就停止定时器
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. 节流阀

  1. 节流阀:防止轮播图按钮连续点击造成播放过快
  2. 目的:上一个动画执行完毕后再执行下一个动画,让事件无法连续触发
  3. 实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
    1. 设置一个变量:var flag = true;
    2. if(flag){flag=flase;do sometiing} 关闭节流阀
    3. 利用回调函数,动画执行完毕 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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值