JavaScript:PC端特效--缓动动画

一、缓动效果原理

缓动动画就是让元素运动速度有所变化,最常见的就是让元素慢慢停下来

思路:

  1. 让盒子每次移动的距离慢慢变小,速度就会慢慢降下来
  2. 核心算法:(目标值-现在位置)/10作为每次移动距离的步长
  3. 停止条件:让盒子位置等于目标位置就停止计时器

案例:点击按钮后盒子缓停

css:

css 复制代码
div {
   position: absolute;
   left: 0;
   top: 40px;
   width: 200px;
   height: 200px;
   background-color: pink;
}

HTML:

html 复制代码
<div></div>
<button>点我开始走</button>

JavaScript:

javascript 复制代码
function annimate(obj, target) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function () {
          var step = (target - obj.offsetLeft) / 10;
          if (obj.offsetLeft == target) {
               clearInterval(obj.timer);
          }
          obj.style.left = obj.offsetLeft + step + 'px';
    }, 15)
}
var div = document.querySelector('div');
var button = document.querySelector('button');
button.addEventListener('click', function () {
    annimate(div, 500);
})

写完运行发现,这个案例有小bug,它并没有准准的停在我们设置的目标位置,因为它涉及到了除法,有小数点后就慢慢没那么精确了

那么我们就把step向上取整,尽量避免小数运算,向上取整是因为能延缓速度的变化,让缓动效果更加柔和

javascript 复制代码
var step = Math.ceil(target - obj.offsetLeft) / 10;

不过这样写忽略了后退时的效果,比如

html 复制代码
<div></div>
<button>点我到500</button>
<button>点我到800</button>
javascript 复制代码
function annimate(obj, target) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function () {
          var step = (target - obj.offsetLeft) / 10;
          if (obj.offsetLeft == target) {
               clearInterval(obj.timer);
          }
          obj.style.left = obj.offsetLeft + step + 'px';
    }, 15)
}
var div = document.querySelector('div');
var btn500 = document.querySelector('.btn500');
var btn800 = document.querySelector('.btn800');
btn500.addEventListener('click', function () {
    annimate(div, 500);
})
btn800.addEventListener('click', function () {
    annimate(div, 800);
})

在这个时候前进能准确到目标位置,但是后退时不能,按照上面修复bug的思路看,是取整出现问题了,和前面相似,后退时应该向下取整

那我们给step加上一个判断条件,如果大于0则向上取整,小于0则向下取整

javascript 复制代码
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);

二、动画函数添加回调函数

回调函数原理:函数可以当成一个参数,把一个函数作为参数传到另一个函数里面,那个函数执行完后再来执行传进去的参数,这个过程叫回调

回调函数写的位置:定时器结束的位置

案例:在移动完后输出你好

css:

css 复制代码
* {
   margin: 0px;
   padding: 0px;
}

div {
   position: absolute;
   left: 0;
   top: 40px;
   width: 200px;
   height: 200px;
   background-color: pink;
}

HTML:

html 复制代码
<div></div>
<button>点我到500</button>
<button>点我到800</button>

JavaScript:

javascript 复制代码
function annimate(obj, target) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function () {
          var step = (target - obj.offsetLeft) / 10;
          if (obj.offsetLeft == target) {
               clearInterval(obj.timer);
                    if (callback) {
                        callback();
                    }
          }
          obj.style.left = obj.offsetLeft + step + 'px';
    }, 15)
}
var div = document.querySelector('div');
var btn500 = document.querySelector('.btn500');
var btn800 = document.querySelector('.btn800');
btn500.addEventListener('click', function () {
    annimate(div, 800, function () {
                alert('你好');
    });
})
btn800.addEventListener('click', function () {
    annimate(div, 800, function () {
                alert('你好');
    });
})

三、动画函数封装到单独JS文件里面

因为以后要常用动画函数,所以我们把它封装到JS文件里面,下次要用直接引用就可以了

步骤:

  1. 单独新建一个JS文件
  2. 把我们写的这个函数复制进JS文件里
  3. 调用JS文件
  4. 直接调用动画函数

案例:鼠标经过它后滑出来'问题反馈'

css:

css 复制代码
.sliderbar {
    position: relative;
    left: -9px;
    height: 40px;
    width: 40px;
    text-align: center;
    line-height: 40px;
    color: #fff;
    background-color: purple;
}

.con {
    position: absolute;
    padding: 0 5px;
    left: -130px;
    height: 40px;
    width: 160px;
    background-color: purple;
    z-index: -1;
}

HTML:

记得不要忘记调用JS文件

html 复制代码
<script src="annimater.js"></script>
html 复制代码
<div class="sliderbar">
   <span>→</span>
   <div class="con">问题反馈</div>
</div>

JavaScript:

javascript 复制代码
var sliderbar = document.querySelector('.sliderbar');
var con = document.querySelector('.con');
sliderbar.addEventListener('mouseenter', function () {
    annimate(con, 40, function () {
          sliderbar.children[0].innerHTML = '←';
    })
})
sliderbar.addEventListener('mouseleave', function () {
    annimate(con, -160,, function () {
          sliderbar.children[0].innerHTML = '→';
    })
})

四、网页特效案例

**案例:**网页轮播图

css:

css 复制代码
.main {
    width: 980px;
    height: 455px;
    margin-left: 242px;
}

.focus {
    position: relative;
    width: 715px;
    height: 455px;
    overflow: hidden;
}

.focus ul {
    position: absolute;
    top: 0;
    left: 0;
    width: 1100%;
}

.focus li {
    float: left;
}

.focus img {
    /* width: 715px; */
    height: 455px;
}

.lft,
.rit {
    background: rgba(72, 68, 69, .3);
    width: 15px;
    height: 20px;
    z-index: 999;
    display: none;
}

.lft {
    position: absolute;
    top: 231px;
    left: 0;
}

.rit {
    position: absolute;
    top: 231px;
    right: 0px;
}

.lft a,
.rit a {
    color: #f9f9f9;
}

.lft,
.rit a:hover {
    color: #ccc;
}

.circle {
    position: absolute;
    bottom: 10px;
    left: 295px;
}

.circle li {
    float: left;
    width: 8px;
    height: 8px;
    border: 2px solid rgba(255, 255, 255, .5);
    margin: 0 3px;
    border-radius: 50%;
    cursor: pointer;
}

.current {
    background-color: #fff;
}

HTML:

html 复制代码
<div class="focus fl">
    <div class="lft"><a href="javascript:;">&lt</a></div>
    <div class="rit"><a href="javascript:;">&gt</a></div>
    <ul>
         <li><a href="#"><img src="images/loginbg.png" alt=""></a></li>
         <li><a href="#"><img src="images/loginbg.png" alt=""></a></li>
         <li><a href="#"><img src="images/loginbg.png" alt=""></a></li>
         <li><a href="#"><img src="images/loginbg.png" alt=""></a></li>
         <li><a href="#"><img src="images/loginbg.png" alt=""></a></li>
         <li><a href="#"><img src="images/loginbg.png" alt=""></a></li>
     </ul>
     <ol class="circle">
     </ol>
</div>

JavaScript:

javascript 复制代码
window.addEventListener('load', function () {
    var lft = document.querySelector('.lft');
    var rit = document.querySelector('.rit');
    var focus = document.querySelector('.focus');
    focus.addEventListener('mouseenter', function () {
        lft.style.display = 'block';
        rit.style.display = 'block';
        clearInterval(timer);
        timer = null;
    })
    focus.addEventListener('mouseleave', function () {
        lft.style.display = 'none';
        rit.style.display = 'none';
        timer = setInterval(function () {
            rit.click();
        }, 2000)
    })
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    for (var i = 0; i < ul.children.length; i++) {
        var li = document.createElement('li');
        li.setAttribute('index', i);
        ol.appendChild(li);
        li.addEventListener('click', function () {
            for (var i = 0; i < ol.children.length; i++) {
                ol.children[i].className = '';
            }
            this.className = 'current';
            var index = this.getAttribute('index');
            num = index;
            circle = index;
            var focusWidth = focus.offsetWidth;
            annimate(ul, -index * 1044);
        })
    }
    ol.children[0].className = 'current';
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    var num = 0;
    var circle = 0;
    rit.addEventListener('click', function () {
        if (num == ul.children.length - 1) {
            ul.style.left = 0;
            num = 0
        }
        num++;
        annimate(ul, -num * 1044)
        circle++;
        if (circle == ol.children.length) {
            circle = 0;
        }
        circleChange();
    })
    lft.addEventListener('click', function () {
        if (num == 0) {
            num = ul.children.length - 1;
            ul.style.left = -num * 1044 + 'px';
        }
        num--;
        annimate(ul, -num * 1044)
        circle--;
        if (circle < 0) {
            circle = ol.children.length - 1;
        }
        circleChange();
    })
    function circleChange() {
        for (var i = 0; i < ul.children.length; i++) {
            ol.children[i].className = '';
            ol.children[circle].className = 'current';
        }
    }
    var timer = setInterval(function () {
        rit.click();
    }, 2000)
})
相关推荐
阳光_你好5 分钟前
简单介绍C++中线性代数运算库Eigen
开发语言·c++·线性代数
守城小轩2 小时前
JavaScript vs Python 用于 Web Scraping(2025):终极对比指南
前端·chrome·chrome devtools·指纹浏览器·浏览器开发·超级浏览器
zfj3212 小时前
H2数据库源码学习+debug, 数据库 sql、数据库引擎、数据库存储从此不再神秘
java·数据库·sql·学习·数据库底层原理
ao_lang4 小时前
掌握Git:版本控制与高效协作指南
git·学习
风逸hhh4 小时前
python打卡day29@浙大疏锦行
开发语言·前端·python
LuckyLay4 小时前
Vue百日学习计划Day33-35天详细计划-Gemini版
前端·vue.js·学习
hy____1235 小时前
C++多态的详细讲解
开发语言·c++
superior tigre5 小时前
C++学习:六个月从基础到就业——C++20:范围(Ranges)进阶
c++·学习·c++20
小葡萄20255 小时前
黑马程序员C++2024版笔记 第0章 C++入门
开发语言·c++·笔记