缓慢动画的原理
匀速动画=盒子当前的位置+固定的值
缓慢动画=盒子当前的位置+变化的值
思路
- 核心算法:(目标值-当前的位置)/n 作为每次移动的步长
- 停止的条件:让盒子当前的位置等于目标的位置,就停止定时器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>缓慢动画的原理</title>
<style>
* {
margin: 0;
padding: 0;
}
img {
position: absolute;
display: block;
width: 200px;
height: 200px;
margin-top: 20px;
border: 1px solid red;
border-radius: 50%;
}
button:nth-of-type(1) {
margin-left: 100px;
}
button:nth-of-type(2) {
margin-left: 1200px;
}
</style>
</head>
<body>
<button>前进</button>
<button>后退</button>
<img src="./image/uos.jpg" alt="">
</body>
<script>
let image = document.querySelector('img');
let bth = document.querySelectorAll('button');
function animate(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)
}
bth[0].addEventListener('click',function () {
animate(image,1250)
})
bth[1].addEventListener('click',function (){
animate(image,0)
})
</script>
</html>
缓慢动画之进阶
步长值需取整
- 如果是正值 则往大取整
- 如果是负值 则往小取整
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>缓慢动画之进阶</title>
<style>
* {
margin: 0;
padding: 0;
}
img {
position: absolute;
display: block;
width: 200px;
height: 200px;
margin-top: 20px;
border: 1px solid red;
border-radius: 50%;
}
button:nth-of-type(1) {
margin-left: 100px;
}
button:nth-of-type(2) {
margin-left: 1200px;
}
</style>
</head>
<body>
<button>前进</button>
<button>后退</button>
<img src="./image/uos.jpg" alt="">
</body>
<script>
let image = document.querySelector('img');
let bth = document.querySelectorAll('button');
function animate(obj,target) {
clearInterval(obj.timer)
obj.timer = setInterval(function (){
//步长值需要取整 如果是正值 则往大取整 如果是负值 则往小取整
var step = (target - obj.offsetLeft) /10;
step = step>0?Math.ceil(step):Math.floor(step)
if(obj.offsetLeft == target){
clearInterval(obj.timer)
}
obj.style.left = obj.offsetLeft+step +'px';
},15)
}
bth[0].addEventListener('click',function () {
animate(image,1250)
})
bth[1].addEventListener('click',function (){
animate(image,0)
})
</script>
</html>
缓慢动画之添加回调函数
回调函数:被作为参数传递的函数
核心思路:回调函数要添加到定时器结束的位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>缓慢动画之添加回调函数</title>
<style>
* {
margin: 0;
padding: 0;
}
img {
position: absolute;
display: block;
width: 200px;
height: 200px;
margin-top: 20px;
border: 1px solid red;
border-radius: 50%;
}
button:nth-of-type(1) {
margin-left: 100px;
}
button:nth-of-type(2) {
margin-left: 1200px;
}
.big {
width: 400px;
height: 400px;
}
.small {
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<button>前进</button>
<button>后退</button>
<img src="./image/uos.jpg" alt="">
</body>
<script>
let image = document.querySelector('img');
let bth = document.querySelectorAll('button');
function animate(obj,target,callback) {
clearInterval(obj.timer)
obj.timer = setInterval(function (){
//步长值需要取整 如果是正值 则往大取整 如果是负值 则往小取整
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';
},15)
}
bth[0].addEventListener('click',function () {
animate(image,1250,function (){
image.className='big'
})
})
bth[1].addEventListener('click',function (){
animate(image,0,function (){
image.className='small'
})
})
</script>
</html>
animate动画函数
animate.js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>引用animate函数</title>
<style>
* {
margin: 0;
padding: 0;
}
.slider-bar {
position: fixed;
bottom: 20px;
right: 0;
width: 40px;
height: 40px;
color: #ffffff;
text-align: center;
line-height: 40px;
}
.con {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 40px;
background-color: purple;
z-index: -1;
}
</style>
</head>
<script src="animate.js"></script>
<body>
<div class="slider-bar">
<span>→</span>
<div class="con">问题反馈</div>
</div>
</body>
<script>
//获取元素
let slider_bar = document.querySelector('.slider-bar');
let con = document.querySelector('.con');
slider_bar.addEventListener('mouseenter',function (){
animate(con,-160,function (){
slider_bar.children[0].innerHTML = '← '
})
});
slider_bar.addEventListener('mouseleave',function (){
animate(con,0,function (){
slider_bar.children[0].innerHTML = '→'
})
})
</script>
</html>
轮播图
轮播图也称为焦点图,是网页中比较常见的网页特效。
功能
animate.js
function animate(obj, target, callback) {
// 清除以前的定时器,只保留当前的计时器
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 如果步长为正值 则取大 如果步长为负值 则取小
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"
}, 15);
}
主文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>轮播图</title>
<style>
* {
margin: 0;
padding: 0;
}
ul, ol, li {
list-style: none;
}
.focus {
position: relative;
overflow: hidden;
width: 960px;
height: 540px;
margin: 20px auto;
}
.arr-left,
.arr-right {
display: none;
position: absolute;
width: 32px;
height: 32px;
padding: 4px;
background-color: #ffffff;
opacity: 0.5;
z-index: 2;
transform: translate(0%, -50%);
}
.arr-left {
left: 0;
top: 50%;
border-radius: 0px 50px 50px 0px;
}
.arr-right {
right: 0;
top: 50%;
border-radius: 50% 0px 0px 50%;
}
.focus ul.picture {
position: absolute;
top: 0;
left: 0;
width: 600%;
}
.focus ul.picture li {
float: left;
}
ul.picture img {
width: 960px;
}
ol {
position: absolute;
left: 50%;
bottom: 20px;
transform: translate(-50%, -50%);
}
ol li {
float: left;
width: 16px;
height: 16px;
margin: 4px;
border-radius: 50%;
background-color: #fff;
opacity: 0.5;
}
.current {
background-color: blue !important;
}
</style>
</head>
<script src="animate.js"></script>
<body>
<div class="focus">
<a href="javascript:;" class="arr-left"><img src="./image/arr-l.png" alt=""></a>
<a href="javascript:;" class="arr-right"><img src="./image/arr-r.png" alt=""></a>
<ul class="picture">
<li><a href="javascript:;"><img src="image/focus1.jpg" alt=""></a></li>
<li><a href="javascript:;"><img src="image/focus2.jpg" alt=""></a></li>
<li><a href="javascript:;"><img src="image/focus3.jpg" alt=""></a></li>
<li><a href="javascript:;"><img src="image/focus4.jpg" alt=""></a></li>
</ul>
<ol>
</ol>
</div>
</body>
<script>
//获取元素
let arr_l = document.querySelector('.arr-left');
let arr_r = document.querySelector('.arr-right');
let focus = document.querySelector('.focus');
let focusWidth = focus.offsetWidth;
//1.鼠标经过焦点图 左右箭头显示 鼠标离开焦点图 左右箭头隐藏
focus.addEventListener('mouseenter', function () {
arr_l.style.display = 'block';
arr_r.style.display = 'block';
clearInterval(timer);
time = null; //清除定时器变量
})
focus.addEventListener('mouseleave', function () {
arr_l.style.display = 'none';
arr_r.style.display = 'none';
timer = setInterval(() => {
arr_r.click()
}, 2000)
})
//2.动态创建li 有几张图片就创建几个li
let ul = focus.querySelector('.picture');
let ol = document.querySelector('ol');
for (let i = 0; i < ul.children.length; i++) {
let li = document.createElement('li');
//为每个li设置自定义属性
li.setAttribute('index',i)
ol.appendChild(li);
//3.点击当前li 并使用排他思想
li.addEventListener('click', function () {
//清除所有li的默认样式
for (let i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
//单独为当前li设置样式
this.className = 'current'
//4.点击li 图片移动至相对应的距离
let index = this.getAttribute('index');
//把index的值赋值给index及circle 以便点击点击ol中的li 使图片与ol中的li保持同步
num = index;
circle = index;
animate(ul, -index * focusWidth)
});
}
ol.children[0].className = 'current';
//5.深克隆ul中的第一个li 并追加到ul后面
let firstLi = ul.children[0].cloneNode(true);
ul.appendChild(firstLi)
//6.点击右侧按钮 图片相对应的滚动一张 利用无缝滚动原理 克隆第一张图片追加到ul后面 声名一个变量num 来实现自增效果;
let num = 0;
let circle = 0;
//开启节流阀
let flag = true;
arr_r.addEventListener('click', function () {
if (flag) {
flag = false;
console.log(flag)
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0
}
num++;
animate(ul, -num * focusWidth, function () {
flag = true;
});
//7.点击右侧按钮 图片及下面的小圆圈相对应滚动
circle++;
if (circle == ol.children.length) {
circle = 0;
}
}
circleChange()
})
//7.点击左侧按钮 图片相对应的滚动一张 利用无缝滚动原理 克隆第一张图片追加到ul后面 声名一个变量num 来实现自增效果;
arr_l.addEventListener('click', function () {
if (flag) {
flag = false;
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * focusWidth;
}
;
num--;
animate(ul, -num * focusWidth, function () {
flag = true;
});
//7.点击右侧按钮 图片及下面的小圆圈相对应滚动
circle--;
if (circle < 0) {
circle = ol.children.length-1 ;
}
circleChange()
}
})
//封装一个清除circle类的函数
function circleChange() {
//清除所有circle的current类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
//留下当前的circle的current类名
ol.children[circle].className = 'current'
}
//开启定时器功能
let timer = setInterval(() => {
arr_r.click()
}, 2000)
</script>
</html>
节流阀
防止轮播图按钮连续点击造成播放过快。
目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
aniamte动画函数之返回顶部
滚动窗口至页面中的任意位置 window.scroll(x,y)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
.slider-bar {
position: absolute;
top: 300px;
left: 50%;
/* 版心的一半 */
margin-left: 600px;
width: 200px;
height: 180px;
text-align: center;
line-height: 180px;
background-color: pink;
}
span {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: none;
}
.w {
width: 1200px;
font-weight: 700;
color: #CCCCCC;
margin: 20px auto;
text-align: center;
}
.header {
height: 120px;
line-height: 120px;
background-color: blueviolet;
}
.banner {
height: 400px;
line-height: 400px;
background-color: red;
}
.main {
height: 1000px;
line-height: 600px;
background-color: #008000;
}
</style>
</head>
<body>
<div class="slider-bar">
<span class="goBack">返回顶部</span>
</div>
<div class="header w"></div>
<div class="banner w"></div>
<div class="main w"></div>
</body>
<script>
//获取元素
let slider_bar = document.querySelector('.slider-bar');
let goBack = document.querySelector('.goBack');
let header = document.querySelector('.header');
let banner = document.querySelector('.banner');
let main = document.querySelector('.main');
let bannerTop = banner.offsetTop;
let sliderTop = slider_bar.offsetTop - banner.offsetTop;
let mainTop = main.offsetTop;
//滚动至bannerTop slider_bar的绝对定位改为固定定位 slider_bar的top值为sliderTop;
document.addEventListener("scroll", function (){
if(window.pageYOffset>=bannerTop){
slider_bar.style.position ='fixed';
slider_bar.style.top =sliderTop+'px'
}else {
slider_bar.style.position ='absolute';
slider_bar.style.top =300+'px'
}
if(window.pageYOffset>=mainTop){
goBack.style.display = 'block'
}else {
goBack.style.display = 'none'
}
})
slider_bar.addEventListener('click',function () {
animate(window,0)
})
function animate(obj,target,callback) {
clearInterval(obj.timer)
obj.timer = setInterval(function (){
//步长值需要取整 如果是正值 则往大取整 如果是负值 则往小取整
var step = (target - window.pageYOffset) /10;
step = step>0?Math.ceil(step):Math.floor(step)
if(window.pageYOffset == target){
clearInterval(obj.timer)
};
//回调函数写在定时器结束的位置上
callback&&callback()
window.scroll(0,window.pageYOffset+step)
},15)
}
</script>
</html>
animate动画函数之筋斗云案例
animate.js
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 调用的时候 callback()
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步长值写到定时器的里面
// 把我们步长值改为整数 不要出现小数的问题
// var step = Math.ceil((target - obj.offsetLeft) / 10);
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();
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
主文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>animate函数之筋斗云</title>
<style>
* {
margin: 0;
padding: 0;
}
ul,li {
list-style: none;
}
a {
color: #0f0f0f;
text-decoration: none;
}
body {
background-color: #000000;
}
.c_nav {
position: relative;
width: 900px;
height: 40px;
margin: 200px auto;
background:#fff url("./image/rss.png") no-repeat scroll center right;
}
ul {
position: absolute;
}
li {
float: left;
width: 84px;
height: 42px;
text-align: center;
line-height: 42px;
}
.cloud {
position: absolute;
width: 83px;
height: 42px;
top: 0;
left: 0;
background: url("./image/cloud.gif") no-repeat;
}
</style>
</head>
<script src="animate.js"></script>
<body>
<div id="c_nav" class="c_nav">
<span class="cloud"></span>
<ul>
<li><a href="javascript:;">首页新闻</a></li>
<li><a href="javascript:;">师资力量</a></li>
<li><a href="javascript:;">活动策划</a></li>
<li><a href="javascript:;">企业文化</a></li>
<li><a href="javascript:;">招聘信息</a></li>
<li><a href="javascript:;">公司简介</a></li>
</ul>
</div>
<script>
//获取元素
let c_nav = document.querySelector('.c_nav');
let cloud = document.querySelector('.cloud');
let lis = document.querySelectorAll('li');
// 鼠标经过li时 把当前的li坐标赋值给cloud 鼠标离开li时 clod的坐标为0 鼠标点击li时 将当前li的坐标赋值给current
current = 0;
for(let i=0;i<lis.length;i++){
lis[i].addEventListener('mouseenter',function () {
animate(cloud,this.offsetLeft)
});
lis[i].addEventListener('mouseleave',function () {
animate(cloud,current)
});
lis[i].addEventListener('click',function () {
current = this.offsetLeft;
})
}
</script>
</body>
</html>
移动端
移动端之触屏事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>移动端触屏事件</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background-color:red;
margin: 20px auto;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script>
let box = document.querySelector('.box')
box.addEventListener('touchstart',function () {
console.log('touchstart')
})
box.addEventListener('touchmove',function () {
console.log('touchmove')
})
box.addEventListener('touchend',function () {
console.log('touchend')
})
</script>
</html>
移动端之触屏事件对象
touchstar touchmove touchend三个事件都会有自己的事件对象
平时都是给元素注册触摸事件 所以重点记住targetTouches
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>移动端触摸事件对象</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
margin: 200px auto;
background-color: red;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script>
let box = document.querySelector('.box');
box.addEventListener('touchstart',function (e) {
console.log(e);
console.log(e.touches[0])
})
box.addEventListener('touchend',function (e) {
console.log(e)
})
</script>
</html>
移动端之拖动元素
注意:手指移动也会触发滚动屏幕 所以阻止默认的屏幕滚动 e.preventDefault()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>移动端拖动元素</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script>
let box = document.querySelector('.box');
//获取盒子原来的位置
let x = 0;
let y = 0;
//获取手指的初始位置
let starX = 0;
let starY =0;
box.addEventListener('touchstart',function(e){
//获取手指初始的坐标
starX = e.targetTouches[0].pageX;
starY = e.targetTouches[0].pageY;
x = this.offsetLeft;
y = this.offsetTop;
})
box.addEventListener('touchmove',function (e){
//获取移动的坐标
let moveX = e.targetTouches[0].pageX -starX;
let moveY = e.targetTouches[0].pageY -starY;
//进行赋值
this.style.left = x +moveX+'px'
this.style.top = y+moveY+'px';
e.preventDefault()
})
</script>
</html>