动画
动画原理

// 动画原理
// 1. 获得盒子当前位置
// 2. 让盒子在当前位置加上1个移动距离
// 3. 利用定时器不断重复这个操作
// 4. 加一个结束定时器的条件
// 5. 注意此元素需要添加定位, 才能使用element.style.left
var div = document.querySelector('div');
var btn = document.querySelector('button');
btn.addEventListener("click", function () {
var timer = setInterval(function () {
if (div.offsetLeft > 400) {
clearInterval(timer);
}
div.style.left = div.offsetLeft + 1 + 'px';
}, 10);
})
动画函数封装
// 给对象添加属性的方法
// var obj = {};
// obj.name = 'andy';
// 动画函数封装
// 用添加对象属性的方式,给不同对象添加不同属性的定时器,节省内存空间
function animate(obj, target, step){
// 另外,在调用函数之前先清楚掉原来的定时器,以免多次点击按钮之后定时器累加造成动画加速
clearInterval(obj.timer);
obj.timer = setInterval(function () {
if (obj.offsetLeft > target) {
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 10);
}
var box1 = document.querySelector('.box1');
var box2 = document.querySelector('.box2');
var box3 = document.querySelector('.box3');
var btn = document.querySelector('button');
// 调用函数
btn.addEventListener("click", function () {
animate(box1, 400, 1);
animate(box2, 500, 3);
animate(box3, 600, 5);
})
缓动动画
缓动动画原理

// 缓动动画原理:
// 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
// 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
// 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
function animate(obj, target, speed){
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 缓动动画需要写在定时器里面
var step = (target - obj.offsetLeft) / speed;
if (obj.offsetLeft > target) {
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 10);
}
var box1 = document.querySelector('.box1');
var box2 = document.querySelector('.box2');
var box3 = document.querySelector('.box3');
var btn = document.querySelector('button');
// 调用函数
btn.addEventListener("click", function () {
animate(box1, 400, 10);
animate(box2, 500, 20);
animate(box3, 600, 40);
})
缓动动画在多个目标点之间的移动
// 缓动动画在多个目标点之间的移动:
function animate(obj, target, speed){
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 缓动动画需要写在定时器里面
// JavaScript中需要避免出现小数,否则会导致移动距离出现偏差
var step = (target - obj.offsetLeft) / speed;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 20);
}
var box1 = document.querySelector('.box1');
var btn = document.querySelector('button');
var flag = true;
// 调用函数
btn.addEventListener("click", function () {
if(flag){
animate(box1, 610, 10);
flag = false;
}else{
animate(box1, 10, 10);
flag = true;
}
})
点击animate按钮,图片会在指定位置来回移动
添加回调函数
回调函数作为参数传进动画函数当中,会在动画效果结束后执行:
// 缓动动画添加回调函数:
function animate(obj, target, callback){
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 缓动动画需要写在定时器里面
// JavaScript中需要避免出现小数,否则会导致移动距离出现偏差
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
clearInterval(obj.timer);
// 回调函数写在清除定时器的判断条件里
if(callback){
callback();
}
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 20);
}
var box1 = document.querySelector('.box1');
var btn = document.querySelector('button');
var flag = true;
// 调用函数
btn.addEventListener("click", function () {
if(flag){
animate(box1, 610, function(){
box1.style.backgroundImage = "url('pic/Megumin.jpg')";
});
flag = false;
}else{
animate(box1, 10, function(){
box1.style.backgroundImage = "url('pic/Kana.jpg')";
});
flag = true;
}
})
上面的例子,缓动动画效果结束后会更改盒子内的图片
JS封装
// 缓动动画添加回调函数:
function animate(obj, target, callback) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 缓动动画需要写在定时器里面
// JavaScript中需要避免出现小数,否则会导致移动距离出现偏差
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
clearInterval(obj.timer);
// 回调函数写在清除定时器的判断条件里
/* if (callback) {
callback();
} */
// 使用逻辑中断来代替判断语句
callback&&callback();
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 20);
}
在使用的时候,别忘了在头文件里引用该js文件:
<script src='animate.js'></script>
轮播图效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
/*清除元素默认的内外边距 */
* {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
}
.main {
width: 610px;
margin: 0 auto;
margin-top: 60px;
}
.focus {
position: relative;
width: 600px;
height: 300px;
border: red 2px solid;
overflow: hidden;
}
img {
width: 600px;
}
li {
list-style: none;
}
ul {
position: absolute;
top: 0;
left: 0;
width: 600%;
}
ul li {
float: left;
}
.arrow-l,
.arrow-r {
display: none;
position: absolute;
top: 50%;
margin-top: -20px;
width: 24px;
height: 40px;
background: rgba(0, 0, 0, .3);
text-align: center;
line-height: 40px;
color: #fff;
font-family: 'icomoon';
font-size: 18px;
z-index: 2;
}
.arrow-r {
right: 0;
}
.circle {
position: absolute;
bottom: 10px;
left: 50px;
}
.circle li {
float: left;
width: 8px;
height: 8px;
/*background-color: #fff;*/
border: 2px solid rgba(255, 255, 255, 0.5);
margin: 0 3px;
border-radius: 50%;
/*鼠标经过显示小手*/
cursor: pointer;
}
.current {
background-color: #fff;
}
</style>
<script src='animate.js'></script>
</head>
<body>
<div class="main">
<div class="focus">
<!-- 左侧按钮 -->
<a href="javascript:;" class="arrow-l">←</a>
<!-- 右侧按钮 -->
<a href="javascript:;" class="arrow-r">→</a>
<!-- 核心的滚动区域 -->
<ul>
<li>
<a href="#"><img
src="https://patchwiki.biligame.com/images/blhx/8/87/1axukjehcwyowqeh8f4xobkbvjyija7.jpg"
alt=""></a>
</li>
<li>
<a href="#"><img
src="https://patchwiki.biligame.com/images/blhx/5/5d/aqs86t38ezjjwl1qjlgz9lylsdcojle.jpg"
alt=""></a>
</li>
<li>
<a href="#"><img
src="https://patchwiki.biligame.com/images/blhx/6/66/ntqh7jf5f4ce20qopr5192qxgadbw2x.jpg"
alt=""></a>
</li>
<li>
<a href="#"><img
src="https://patchwiki.biligame.com/images/blhx/f/f4/izxkrqb9iey4ooqws4dimq8r0yttx7b.jpg"
alt=""></a>
</li>
<li>
<a href="#"><img
src="https://patchwiki.biligame.com/images/blhx/3/33/0kz6xpi03oisfing6l3w4547hag1kpr.jpg"
alt=""></a>
</li>
</ul>
<!-- 小圆圈 -->
<ol class="circle">
</ol>
</div>
</div>
<script>
// 网页轮播图
// 需求:
// 1. 鼠标经过轮播图模块,左右按钮显示,离开即隐藏两个按钮
// 2. 点击右侧按钮一次,图片往左播放一次,反之则向右播放一张
// 3. 图片播放时,下面的小圆点跟随一起变化
// 4. 点击小圆点,可以播放对应的图片
// 5. 鼠标不经过轮播图模块,会自动播放图片
// 6. 鼠标经过时,自动播放停止
// 获取元素
var box = document.querySelector('.focus');
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var pic = document.querySelector('img');
var ul = document.querySelector('ul');
var ol = document.querySelector('.circle');
var num = 0;
var dot = 0;
var flag = true; // 节流阀
// 显示/隐藏箭头
box.addEventListener('mouseenter', function () {
arrow_l.style.display = 'block'
arrow_r.style.display = 'block'
clearInterval(timer);
timer = null; // 清楚定时器变量
});
box.addEventListener('mouseleave', function () {
arrow_l.style.display = 'none'
arrow_r.style.display = 'none'
timer = setInterval(function () {
arrow_r.click();
}, 2000);
});
// 动态生成小圆圈
// console.log(pic.length);
for (var i = 0; i < ul.children.length; i++) {
var li = document.createElement('li');
li.setAttribute('index', i);
ol.append(li);
// 小圆圈的排他算法
li.addEventListener('click', function () {
for (var j = 0; j < ol.children.length; j++) {
ol.children[j].className = '';
}
this.className = 'current';
// 对应图片跳转
var index = this.getAttribute('index');
// console.log(index);
animate(ul, -index * pic.clientWidth);
num = index;
dot = index;
})
}
ol.children[0].className = 'current';
/* ol.addEventListener('click',function(e){
for(var i = 0; i < ul.children.length; i++){
ol.children[i].className = '';
}
e.target.className = 'current';
console.log(e.target);
}) */
// 这里虽然想到用事件委托,虽然点击圆点也能实现相应效果
// 但是如果不小心点到圆点之间的间隔,e.target会判定是ol,所有小圆点都会消失
// 将第一张图片复制到最后面,利用视觉差来做出循环效果
// 因为克隆是在小圆点生成之后,所以不会影响小圆点的总数量
var firstPic = ul.children[0].cloneNode(true); // 完全克隆
ul.appendChild(firstPic);
// 点击箭头跳转图片
arrow_r.addEventListener('click', function () {
if (flag) {
flag = false; // 关闭节流阀
// 图片无缝滚动
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * pic.clientWidth, function () {
flag = true; // 打开节流阀
});
dot++;
if (dot == ol.children.length) {
dot = 0;
}
circleChange();
}
});
arrow_l.addEventListener('click', function () {
if (flag) {
flag = false;
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * pic.clientWidth + 'px';
}
num--;
animate(ul, -num * pic.clientWidth, function(){
flag = true;
});
dot--;
dot = dot < 0 ? ol.children.length - 1 : dot;
circleChange();
}
});
// 更改圆点位置
function circleChange() {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
ol.children[dot].className = 'current';
};
// 自动轮播功能
var timer = setInterval(function () {
// 手动调用事件
arrow_r.click();
}, 2000);
</script>
</body>
</html>
说明一下什么是节流阀:

返回顶部动画
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
.slide-bar {
position: absolute;
left: 50%;
top: 300px;
margin-left: 600px;
width: 45px;
height: 130px;
background-color: pink;
}
.w {
width: 1200px;
margin: 10px auto;
}
.header {
height: 150px;
background-color: purple;
}
.banner {
height: 250px;
background-color: skyblue;
}
.main {
height: 1000px;
background-color: yellowgreen;
}
span {
display: none;
position: absolute;
bottom: 0;
}
.goBack {
display: none;
}
</style>
</head>
<body>
<div class="slide-bar">
<a class="goBack">Top</a>
</div>
<div class="header w">Header</div>
<div class="banner w">Bannner</div>
<div class="main w">Main</div>
<script>
// 仿淘宝侧边固定栏
var slide_bar = document.querySelector('.slide-bar');
var banner = document.querySelector('.banner');
var bannerTop = banner.offsetTop;
var slideBarTop = slide_bar.offsetTop - bannerTop;
var main = document.querySelector('.main');
var btn = document.querySelector('.goBack');
var mainTop = main.offsetTop;
// 页面滚动事件
document.addEventListener('scroll', function () {
// window.pageYOffset 页面被卷去的头部
console.log(window.pageYOffset);
// 当页面卷到banner栏时,固定slideBar在页面的显示位置,
if (window.pageYOffset >= bannerTop) {
slide_bar.style.position = 'fixed'
slide_bar.style.top = slideBarTop + 'px';
} else {
slide_bar.style.position = 'absolute';
slide_bar.style.top = '300px';
}
// 当页面卷到main盒子时,显示top模块
if (window.pageYOffset >= mainTop) {
btn.style.display = 'block';
} else {
btn.style.display = 'none';
}
});
slide_bar.addEventListener('click',function(){
animate(window, 0);
})
// 缓动动画添加回调函数:
function animate(obj, target, callback) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 缓动动画需要写在定时器里面
// JavaScript中需要避免出现小数,否则会导致移动距离出现偏差
var step = (target - window.pageYOffset) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (window.pageYOffset == target) {
clearInterval(obj.timer);
// 回调函数写在清除定时器的判断条件里
/* if (callback) {
callback();
} */
// 使用逻辑中断来代替判断语句
callback && callback();
}
// obj.style.left = obj.offsetLeft + step + 'px';
window.scroll(0, window.pageYOffset + step);
}, 20);
}
</script>
</body>
</html>
其实只需要把动画的目标地点从水平更改为垂直就行了
网友评论