Slow animation
Principle of slow animation
Slow animation is to make the movement speed of the element change, the most common slow animation is to stop the animation speed slowly
Core idea
- Slowly reduce the distance the box moves each time, and the speed will gradually decrease
- Core algorithm: (target value-current position)/10 as the distance step of each movement
- Stop condition: Let the current position of the box equal to the target position, then stop the timer
- Note that the step value needs to be rounded
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
button {
margin: 50px;
}
img {
position: absolute;
display: block;
width: 200px;
height: 200px;
border-radius: 50%;
}
</style>
</head>
<body>
<img src="./image/picture.jpg" alt="" class="img">
<button>点击移动至800</button>
<button>点击移动至0</button>
<script>
var bth = document.querySelectorAll('button');
var img = document.querySelector('img')
// obj:目标对象 target:目标位置
function aniamte(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() {
aniamte(img, 800)
})
bth[1].addEventListener('click', function() {
aniamte(img, 0)
})
</script>
</body>
</html>
Add callback function for slow animation
Core idea: The callback function should be added to the end of the timer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
button {
margin: 50px;
}
img {
position: absolute;
display: block;
width: 200px;
height: 200px;
border-radius: 50%;
}
.photo {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<button>点击移动至800</button>
<button>点击移动至0</button>
<img src="./image/picture.jpg" alt="" class="img">
<script>
var bth = document.querySelectorAll('button');
var img = document.querySelector('img')
// obj:目标对象 target:目标位置
function aniamte(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() {
aniamte(img, 800, function() {
img.className = 'img'
})
})
bth[1].addEventListener('click', function() {
aniamte(img, 0, function() {
img.className = 'photo img'
})
})
</script>
</body>
</html>
animate animation function
animate.js file
var bth = document.querySelectorAll('button');
var img = document.querySelector('img')
// obj:目标对象 target:目标位置
function aniamte(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() {
aniamte(img, 800, function() {
img.className = 'img'
})
})
bth[1].addEventListener('click', function() {
aniamte(img, 0, function() {
img.className = 'photo img'
})
})
Master file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.sliderbar {
position: fixed;
right: 0;
bottom: 100px;
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
color: #fff;
cursor: pointer;
}
.con {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 40px;
background-color: purple;
z-index: -1;
}
</style>
<script src="./animate.js"></script>
</head>
<body>
<div class="sliderbar">
<span> ← </span>
<div class="con">问题反馈</div>
</div>
<script>
var sliderbar = document.querySelector('.sliderbar');
var con = document.querySelector('.con');
sliderbar.addEventListener('mouseenter', function() {
aniamte(con, -160, function() {
sliderbar.children[0].innerHTML = "→"
})
})
sliderbar.addEventListener('mouseleave', function() {
aniamte(con, 0, function() {
sliderbar.children[0].innerHTML = "← "
})
})
</script>
</body>
</html>
Carousel
The carousel picture is also called the focus picture, which is a common webpage special effect in the webpage.
Functional Requirements:
1. The mouse passes over the carousel diagram module, the left and right buttons are displayed, and when left, the left and right buttons are hidden.
2. Click the right button once, the picture will be played to the left, and so on, the left button is the same.
3. While the picture is playing, the small circle module below changes along with it.
4. Click the small circle to play the corresponding picture.
5. If the mouse does not pass the carousel picture, the carousel picture will automatically play the picture.
6. Mouse over, carousel picture module, auto play stop
animate.js
function aniamte(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);
}
Master file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮播图</title>
<style>
* {
margin: 0;
padding: 0;
}
ul,
ol {
list-style: none;
}
.foucs {
overflow: hidden;
position: relative;
width: 990px;
height: 540px;
margin: 200px auto;
}
a {
display: none;
position: absolute;
width: 40px;
height: 40px;
color: white;
top: 50%;
transform: translateY(-50%);
text-decoration: none;
text-align: center;
line-height: 40px;
font-size: 20px;
background-color: rgba(0, 0, 0, 0.5);
}
.arrow-l {
left: 0;
border-radius: 0px 20px 20px 0px;
}
.arrow-r {
right: 0;
border-radius: 20px 0px 0px 20px;
}
.Picture {
/* 注意 ul移动 所以必须要加定位 */
position: absolute;
top: 0;
left: 0;
width: 600%;
z-index: -1;
}
.Picture li {
float: left;
}
.Picture li img {
width: 990px;
height: 540px;
}
.circle {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 20px;
height: 40px;
border-radius: 20px;
background-color: rgba(0, 0, 0, 0.5);
}
.circle li {
float: left;
width: 10px;
height: 10px;
margin: 15px;
background-color: white;
border-radius: 50%;
}
.circle .curent {
background-color: red;
}
</style>
</head>
<script type="text/javascript" src="./animate.js">
</script>
<body>
<div class="foucs">
<!-- 左右箭头 -->
<a href="javascript:;" class="arrow-l">
<</a> <a href="javascript:;" class="arrow-r"> >
</a>
<!-- 图片容器 -->
<ul class="Picture">
<li><img src="./image/focus1.jpg" alt=""></li>
<li><img src="./image/focus2.jpg" alt=""></li>
<li><img src="./image/focus3.jpg" alt=""></li>
<li><img src="./image/focus4.jpg" alt=""></li>
</ul>
<!-- 底部导航 -->
<ol class="circle">
</ol>
</div>
<script>
// 1.获取元素
var focus = document.querySelector(".foucs")
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
/*获取ul的宽度*/
var fousWidth = focus.offsetWidth;
console.log(fousWidth)
var ul = document.querySelector('.Picture');
var ol = document.querySelector('.circle');
// 克隆第一张照片
//2.绑定事件 鼠标经过轮播图模块的时候 左右箭头会显示 鼠标离开轮播图的时候 左右箭头会消失
focus.addEventListener('mouseenter', function() {
arrow_l.style.display = 'block';
arrow_r.style.display = 'block';
clearInterval(timer)
})
focus.addEventListener('mouseleave', function() {
arrow_l.style.display = 'none';
arrow_r.style.display = 'none';
timer = setInterval(function(){
arrow_r.click()
},2000)
})
//3.动态创建小圆圈 有几张图片就想对应的创建几个小圆圈
for (var i = 0; i < ul.children.length; i++) {
// 创建li
var li = document.createElement('li');
// 为li设置自定义属性
li.setAttribute('index', i)
// 追加到ul里面
ol.append(li);
//4.点击当前的小圆圈,给当前的小圆圈添加类,同时使用排他思想清除其它li的样式
li.addEventListener('click', function() {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
};
this.className = 'curent';
/* 5.为li设置自定义属性,点击小圆圈,ul的移动距离是索引号乘以容器的宽度 注意为负值*/
var index = this.getAttribute('index');
/*把index的值赋值给circle及num 以保持播放图片时图片和小圆圈能保持同步*/
num = index;
circle = index;
aniamte(ul, -index * fousWidth)
})
}
//6.点击右侧按钮 图片滚动一张 利用无缝滚动要克隆第一张图片,追加到ul后面,进行判断 注意声明一个变量num实现自增效果
var first = ul.children[0].cloneNode(true);
ul.append(first);
var num = 0;
var circle = 0;
// 开启节流阀
var flag = true;
arrow_r.addEventListener('click', function() {
if(flag){
flag = false;
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0
}
num++;
aniamte(ul, -num * fousWidth, function(){
flag = true;
});
// 7.点击右侧按钮,小圆圈跟随一起变化,声明一个变量circle来控制小圆圈的播放
circle++;
if (circle == ol.children.length) {
circle = 0;
}
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
ol.children[circle].className = 'curent'
}
})
//左侧按钮做法
arrow_l.addEventListener('click', function() {
if(flag) {
// 关闭节流阀
flag = false;
if (num == 0) {
num= ul.children.length-1;
ul.style.left = -num * fousWidth +"px"
}
num--;
aniamte(ul, -num * fousWidth,function(){
// 开启节流阀
flag = true;
});
// 7.点击右侧按钮,小圆圈跟随一起变化,声明一个变量circle来控制小圆圈的播放
circle--;
// 如果circle<0,则代表目前处于第一张图片 ,则小圆圈的索引为3
if (circle <0 ) {
circle = ol.children.length-1;
}
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
ol.children[circle].className = 'curent'
}
})
// 8.开启自动播放功能
var timer = setInterval(function(){
arrow_r.click()
},2000)
// 将ol里面的第一个li设置为红色 也就是添加.curent类名
ol.children[0].className = 'curent'
</script>
</html>
Throttle valve
Prevent the continuous click of the carousel button from causing excessively fast playback.
The purpose of the throttle: When the content of the previous function animation is executed, the next function animation is executed, so that the event cannot be triggered continuously.
Core realization idea: use callback function, add a variable to control, lock function and unlock function.
aniamte animation function back to top
Scroll the window to any position on the page 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;
background-color: blueviolet;
}
.banner {
height: 400px;
background-color: red;
}
.main {
height: 2000px;
background-color: #008000;
}
</style>
</head>
<body>
<div class="slider-bar">
<span class="goBack">返回顶部</span>
</div>
<div class="header w">header</div>
<div class="banner w">banner</div>
<div class="main w">主体</div>
</body>
<script>
//获取元素
var slider = document.querySelector('.slider-bar');
var goBack = document.querySelector('.goBack');
var header = document.querySelector('.header');
var banner = document.querySelector('.banner');
var main = document.querySelector('.main');
//bannerTop就是被卷去头部的大小,一定要写到滚动的外面 mainTop同理
var mainTop = main.offsetTop;
var bannerTop = banner.offsetTop;
var sliderbarTop = slider.offsetTop - bannerTop;
// 绑定scroll事件
document.addEventListener('scroll', function() {
if (window.pageYOffset >= bannerTop) {
slider.style.position = 'fixed'
slider.style.top = sliderbarTop + "px"
} else {
slider.style.position = 'absolute';
slider.style.top = "300px"
}
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block'
} else {
goBack.style.display = 'none'
}
})
//当我们点击返回顶部模块,就让窗口滚动至页面的最顶部
goBack.addEventListener('click', function() {
animate(window, 0)
})
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 - window.pageYOffset) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (window.pageYOffset == target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
// 回调函数写到定时器结束里面
// if (callback) {
// // 调用函数
// callback();
// }
callback && callback();
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
// obj.style.left = window.pageYOffset + step + 'px';
window.scroll(0, window.pageYOffset + step);
}, 15);
}
</script>
</html>
Somersault cloud case of animate function
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);
}
Master file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>筋斗云案例</title>
<script src="animate.js"></script>
</head>
<style>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
body {
background-color: black;
}
.c-nav {
position: relative;
width: 900px;
height: 42px;
background: #fff url(image/rss.png) no-repeat right center;
margin: 100px auto;
}
.c-nav ul {
position: absolute;
}
.c-nav li {
float: left;
width: 83px;
text-align: center;
line-height: 42px;
}
.c-nav li a {
color: #333;
text-decoration: none;
display: inline-block;
height: 42px;
}
.c-nav li a:hover {
color: white;
}
.cloud {
position: absolute;
left: 0;
top: 0;
width: 83px;
height: 42px;
background: url(image/cloud.gif) no-repeat;
}
</style>
<body>
<div id="c_nav" class="c-nav">
<span class="cloud"></span>
<ul>
<li class="current"><a href="#">首页新闻</a></li>
<li><a href="#">师资力量</a></li>
<li><a href="#">活动策划</a></li>
<li><a href="#">企业文化</a></li>
<li><a href="#">招聘信息</a></li>
<li><a href="#">公司简介</a></li>
<li><a href="#">我是佩奇</a></li>
<li><a href="#">啥是佩奇</a></li>
</ul>
</div>
</body>
<script>
//获取事件源
var c_nav = document.querySelector('#c_nav');
var cloud = document.querySelector('.cloud');
var lis = c_nav.querySelectorAll('li');
console.log(lis)
//声明current变量作为筋斗云的起始位置
var current = 0;
// 给每个li绑定事件
for (var i = 0; i < lis.length; i++) {
// 鼠标经过的时候
lis[i].addEventListener('mouseenter', function() {
aniamte(cloud, this.offsetLeft)
})
// 鼠标离开的时候
lis[i].addEventListener('mouseleave', function() {
aniamte(cloud, current)
})
// 鼠标点击的时候
lis[i].addEventListener('click', function() {
current = this.offsetLeft;
})
}
</script>
</html>
Mobile
Touch screen events on mobile
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>移动端触摸事件</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var box = document.querySelector('.box');
box.addEventListener('touchstart', function() {
console.log('touchstar')
})
box.addEventListener('touchmove', function() {
console.log('touchmove')
})
box.addEventListener('touchend', function() {
console.log('touchend')
})
</script>
</body>
</html>
Touch screen event object on mobile
touchstar touchmove touchend three events will have their own event object
Usually register touch events for elements, so focus on targetTouches
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>移动端触摸事件</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var box = document.querySelector('.box');
box.addEventListener('touchstart', function(e) {
console.log(e.targetTouches[0]);
})
</script>
</body>
</html>
Drag element on mobile
(1) Touch element touchstar: Get the initial coordinates of the finger. At the same time get the original position of the box
(2) Move event touchmove: get the sliding distance of the finger, and move the box
Note: Finger movement will also trigger the scrolling of the screen, so prevent the default screen scrolling e.preventDefault()
<!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>
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div></div>
<script>
var div = document.querySelector('div');
var startX = 0; //获取手指初始坐标
var startY = 0;
var x = 0; //获得盒子原来的位置
var y = 0;
div.addEventListener('touchstart', function(e) {
// 获取手指初始坐标
startX = e.targetTouches[0].pageX;
startY = e.targetTouches[0].pageY;
x = this.offsetLeft;
y = this.offsetTop;
});
div.addEventListener('touchmove', function(e) {
// 计算手指的移动距离: 手指移动之后的坐标减去手指初始的坐标
var moveX = e.targetTouches[0].pageX - startX;
var moveY = e.targetTouches[0].pageY - startY;
// 移动我们的盒子 盒子原来的位置 + 手指移动的距离
this.style.left = x + moveX + 'px';
this.style.top = y + moveY + 'px';
e.preventDefault(); // 阻止屏幕滚动的默认行为
});
</script>
</body>
</html>