一、缓动效果原理
缓动动画就是让元素运动速度有所变化,最常见的就是让元素慢慢停下来
思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢降下来
- 核心算法:(目标值-现在位置)/10作为每次移动距离的步长
- 停止条件:让盒子位置等于目标位置就停止计时器
案例:点击按钮后盒子缓停
css:
div {position: absolute;left: 0;top: 40px;width: 200px;height: 200px;background-color: pink;
}
HTML:
<div></div>
<button>点我开始走</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 button = document.querySelector('button');
button.addEventListener('click', function () {annimate(div, 500);
})
写完运行发现,这个案例有小bug,它并没有准准的停在我们设置的目标位置,因为它涉及到了除法,有小数点后就慢慢没那么精确了
那么我们就把step向上取整,尽量避免小数运算,向上取整是因为能延缓速度的变化,让缓动效果更加柔和
var step = Math.ceil(target - obj.offsetLeft) / 10;
不过这样写忽略了后退时的效果,比如
<div></div>
<button>点我到500</button>
<button>点我到800</button>
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则向下取整
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
二、动画函数添加回调函数
回调函数原理:函数可以当成一个参数,把一个函数作为参数传到另一个函数里面,那个函数执行完后再来执行传进去的参数,这个过程叫回调
回调函数写的位置:定时器结束的位置
案例:在移动完后输出你好
css:
* {margin: 0px;padding: 0px;
}div {position: absolute;left: 0;top: 40px;width: 200px;height: 200px;background-color: pink;
}
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);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文件里面,下次要用直接引用就可以了
步骤:
- 单独新建一个JS文件
- 把我们写的这个函数复制进JS文件里
- 调用JS文件
- 直接调用动画函数
案例:鼠标经过它后滑出来‘问题反馈’
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文件
<script src="annimater.js"></script>
<div class="sliderbar"><span>→</span><div class="con">问题反馈</div>
</div>
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:
.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:
<div class="focus fl"><div class="lft"><a href="javascript:;"><</a></div><div class="rit"><a href="javascript:;">></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:
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)
})