一、缓动效果原理
缓动动画就是让元素运动速度有所变化,最常见的就是让元素慢慢停下来
思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢降下来
- 核心算法:(目标值-现在位置)/10作为每次移动距离的步长
- 停止条件:让盒子位置等于目标位置就停止计时器
案例:点击按钮后盒子缓停
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文件里面,下次要用直接引用就可以了
步骤:
- 单独新建一个JS文件
- 把我们写的这个函数复制进JS文件里
- 调用JS文件
- 直接调用动画函数
案例:鼠标经过它后滑出来'问题反馈'
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:;"><</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:
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)
})