一、匀速运动
运动是javascript动画的一个基本操作。通过css3属性的transition和animation可以实现运动。(后面的css3章节会详细讲解)。但是要进行更精细的操作,javascript运动是必不可少的。
1、简单运动
让一个元素在页面中运动起来很简单,设置定时器,改变定位元素的left和top值即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01 匀速运动</title>
<style>
*{
padding: 0;
margin: 0;
}
#btn{
width: 100px;
height: 30px;
}
#box{
width: 150px;
height: 150px;
border: 1px solid pink;
background-color:pink;
position: absolute;
top: 50px;
}
</style>
</head>
<body>
<button id="btn">运动</button>
<div id="box"></div>
<script>
//1、获取事件源
var btn = document.getElementById('btn');
var box = document.getElementById('box');
var timer = null;
//2、给按钮绑定事件
btn.onclick = function(){
//重复点击按钮的时候要先清除按钮的定时器
clearInterval(timer);
//3、让盒子运动起来
timer = setInterval(function(){
//3.1判断临界点
if(box.offsetLeft === 500){
clearInterval(timer);
}else{
box.style.left = box.offsetLeft +10 +'px';
}
},30)
}
</script>
</body>
</html>
2、实现一个简单的侧边栏分享效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02 简单的侧边栏分享效果</title>
<style>
*{
padding: 0;
margin: 0;
}
#box{
width: 200px;
height: 200px;
background-color:red;
position: relative;
left: -200px;
}
#box span{
width: 40px;
height: 60px;
color: #ffffff;
background-color: #000000;
line-height: 60px;
text-align: center;
position: absolute;
left:200px;
top: 50%;
margin-top: -30px;
}
</style>
</head>
<body>
<div id="box">
<span>拉开</span>
</div>
<script>
window.onload = function(){
var box = document.getElementById('box');
box.onmouseover = function(){
this.style.left = 0 + 'px';
}
box.onmouseout = function(){
this.style.left = -200 + 'px';
}
}
</script>
</body>
</html>
3、实现侧边栏匀速运动的效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03 侧边栏的匀速运动效果</title>
<style>
*{
padding: 0;
margin: 0;
}
#box{
width: 200px;
height: 200px;
background-color:red;
position: relative;
left: -200px;
}
#box span{
width: 40px;
height: 60px;
color: #ffffff;
background-color: #000000;
line-height: 60px;
text-align: center;
position: absolute;
left:200px;
top: 50%;
margin-top: -30px;
}
</style>
</head>
<body>
<div id="box">
<span>拉开</span>
</div>
<script>
window.onload = function(){
var box = document.getElementById('box');
var timer = null;
box.onmouseover = function(){
clearInterval(timer);
timer = setInterval(function(){
if(box.offsetLeft === 0){
clearInterval(timer);
return;
}
box.style.left = box.offsetLeft + 5 +'px';
},30);
}
box.onmouseout = function(){
clearInterval(timer);
timer = setInterval(function(){
if(box.offsetLeft === -200){
clearInterval(timer);
return;
}
box.style.left = box.offsetLeft - 5 +'px';
},30);
}
}
</script>
</body>
</html>
4、匀速运动函数封装
以上代码我们很容易就发现匀速运动代码的冗余性,要解决这个问题呢,我们就要把匀速运动的函数封装起来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>匀速运动的封装函数</title>
<style>
*{
padding: 0;
margin: 0;
}
#box{
width: 200px;
height: 200px;
background-color:red;
position: relative;
left: -200px;
}
#box span{
width: 40px;
height: 60px;
color: #ffffff;
background-color: #000000;
line-height: 60px;
text-align: center;
position: absolute;
left:200px;
top: 50%;
margin-top: -30px;
}
</style>
</head>
<body>
<div id="box">
<span>拉开</span>
</div>
<script>
window.onload = function(){
var box = document.getElementById('box');
var timer = null, speed = 0;
box.onmouseover = function(){
startAnimation(this,0);
}
box.onmouseout = function(){
startAnimation(this,-200);
}
//匀速运动的函数封装
function startAnimation(obj,end){
clearInterval(timer);
speed = end > obj.offsetLeft? 5:-5;
timer = setInterval(function(){
if(box.offsetLeft === end){
clearInterval(timer);
return;
}
box.style.left = box.offsetLeft + speed +'px';
},30);
}
}
</script>
</body>
</html>
二、缓动运动
1、缓动的基本动画
缓动运动的动画公式:加速度 = (结束值 - 起始值)/ 缓动系数; 加速度是由快到慢的 起始值就是offsetLet 缓动系数是由自己定义的
加速度的值要取整
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04 侧边栏的缓动运动效果</title>
<style>
*{
padding: 0;
margin: 0;
}
#box{
width: 200px;
height: 200px;
background-color:red;
position: relative;
left: -200px;
}
#box span{
width: 40px;
height: 60px;
color: #ffffff;
background-color: #000000;
line-height: 60px;
text-align: center;
position: absolute;
left:200px;
top: 50%;
margin-top: -30px;
}
</style>
</head>
<body>
<div id="box">
<span>拉开</span>
</div>
<script>
//0~200;
//缓动运动的动画公式:加速度 = (结束值 - 起始值)/ 缓动系数; 加速度是由快到慢的 起始值就是offsetLet 缓动系数是由自己定义的
window.onload = function(){
var box = document.getElementById('box');
var timer = null,end = 0,end2 = -200;
box.onmouseover = function(){
clearInterval(timer);
timer = setInterval(function(){
speed = Math.ceil((end - box.offsetLeft)/20);//给加速度的值取整
if(box.offsetLeft === end){
clearInterval(timer);
return;
}
box.style.left = box.offsetLeft + speed +'px';
},30)
}
box.onmouseout = function(){
clearInterval(timer);
timer = setInterval(function(){
speed = Math.floor((end2 - box.offsetLeft)/20);//给加速度的值取整
if(box.offsetLeft === end2){
clearInterval(timer);
return;
}
box.style.left = box.offsetLeft + speed +'px';
},30)
}
}
</script>
</body>
</html>
2、缓动运动函数封装
<script>
function slowAnimation(obj,end){
clearInterval(timer);
timer = setInterval(function(){
speed = (end - obj.offsetLeft)/20;
speed = speed >0 ? Math.ceil(speed) : Math.floor(speed);
if(obj.offsetLeft === end){
clearInterval(timer);
return;
}
obj.style.left = obj.offsetLeft + speed +'px';
},30)
}
}
</script>
三、透明度运动
opacity:1属性是表示透明度的,默认为最大值1,最小值是0(但是这个属性在ie8以下的浏览器不兼容)
filter: alpha(opacity:100) 是ie8以下浏览器的透明度属性,最大值为100;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05 透明度动画</title>
<style>
* {
padding: 0;
margin: 0;
}
#box {
width: 200px;
height: 200px;
background-color: red;
opacity: 0.3;
/* filter: alpha(opacity:30);这是ie8以下的浏览器中的透明度属性 */
}
</style>
</head>
<body>
<div id="box">
</div>
<script>
window.onload = function () {
var box = document.getElementById('box');
box.onmouseover = function () {
alphaAnimation(this, 100);
}
box.onmouseout = function () {
alphaAnimation(this, 30);
}
var timer = null,speed = 0, alpha = 30; //speed是透明度变化的速度 alpha是物体起始的透明度
function alphaAnimation(obj, endAlpha) { //endAlpha是结束时的透明度值
clearInterval(timer);
timer = setInterval(function () {
speed = endAlpha > alpha ? 5 : -5;
//处理边界
if (alpha === endAlpha) {
clearInterval(timer);
return;
}
//改变当前的alpha值
alpha += speed;
//修改透明度的值
obj.style.opacity = alpha / 100;
// obj.style.filter = ` alpha(opacity:${alpha})`;
}, 30)
}
}
</script>
</body>
</html>
四、多物体动画
如果在页面中有多个元素利用运动函数进行运动。由于定时器返回值在不同元素上时不同的返回值。所以要将全局的定时器挂载到当前的元素之上。
针对于多物体运动,定时器的返回值要绑定当前的对象中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06 多物体运动</title>
<style>
* {
padding: 0;
margin: 0;
}
div {
width: 300px;
height: 100px;
margin-top: 50px;
background-color: green;
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
<script>
window.onload = function () {
//1、获取标签
//缓动运动的动画公式:加速度 = (结束值 - 起始值)/ 缓动系数; 加速度是由快到慢的 起始值就是offsetLet 缓动系数是由自己定义的
var oDiv = document.getElementsByTagName('div');
for (var i = 0 ; i < oDiv.length; i++) {
oDiv[i].onmouseover = function () {
startAnimation(this, 600);
}
oDiv[i].onmouseout = function () {
startAnimation(this, 300);
}
}
var speed = 0;
function startAnimation(obj, end) {
//开启定时器之前、清除定时器
clearInterval(obj.timer);
obj.timer = setInterval(function () {
//speed是变化的速度
speed = (end - obj.offsetWidth) / 10;
speed = end > obj.offsetWidth ? Math.ceil(speed):Math.floor(speed);
//临界处理
if(end === obj.offsetWidth){
clearInterval(obj.timer);
return;
}
//宽度变化
obj.style.width = obj.offsetWidth + speed + 'px';
}, 30);
}
}
</script>
</body>
</html>
2、get.ComputedStyle()和obj.currentStyle
针对于上面的代码,会有一个bug,当你给元素对象加一个border属性的时候,上面代码就会出现问题,要解决这个问题就需要用到get.ComputedStyle()和obj.currentStyle这个两种方法,前者是用于主流浏览器,后者是用于ie浏览器
多物体运动完整版代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>08 多物体运动的完整版</title>
<style>
* {
padding: 0;
margin: 0;
}
div {
width: 300px;
height: 100px;
margin-top: 50px;
background-color: green;
border: 5px solid #000000;
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
<script>
window.onload = function () {
//1、获取标签
//缓动运动的动画公式:加速度 = (结束值 - 起始值)/ 缓动系数; 加速度是由快到慢的 起始值就是offsetLet 缓动系数是由自己定义的
var oDiv = document.getElementsByTagName('div');
for (var i = 0 ; i < oDiv.length; i++) {
oDiv[i].onmouseover = function () {
startAnimation(this, 600);
}
oDiv[i].onmouseout = function () {
startAnimation(this, 300);
}
}
var speed = 0;
function startAnimation(obj, end) {
//针对于多物体运动,定时器的返回值要绑定在当前的事件中
clearInterval(obj.timer);
obj.timer = setInterval(function () {
//0、获取样式属性
var cur = parseInt(getStyle(obj,'width'));
//1、求速度
speed = (end - cur) / 10;
speed = end > cur ? Math.ceil(speed):Math.floor(speed);
//2、临界处理
if(end === cur){
clearInterval(obj.timer);
return;
}
//3、运动起来
obj.style.width = cur + speed + 'px';
}, 30);
}
//obj是当前元素对象 attr是当前元素对象的属性
function getStyle(obj, attr) {
if (obj.currentStyle) {
//obj.currentStyle是兼容ie的方法
return obj.currentStyle[attr];
} else {
//主流浏览器的方法
return getComputedStyle(obj, null)[attr];
}
}
}
五、多值运动
1、元素属性的多值运动
多物体运动同时改变的是同一个属性,如果我想既可以改变一个元素的宽度,又可以改变一个盒子的高度呢?如何去做?
上述代码中,在最后修改元素的width时,可以有如下书写方式ele.style['width'] = cur + speed + 'px';这样的话,就可以将属性当做形参放到封装的函数中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>09 多值运动</title>
<style>
* {
padding: 0;
margin: 0;
}
div {
width: 300px;
height: 100px;
margin-top: 50px;
background-color: green;
border: 5px solid #000000;
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
<script>
window.onload = function () {
//1、获取标签
//缓动运动的动画公式:加速度 = (结束值 - 起始值)/ 缓动系数; 加速度是由快到慢的 起始值就是offsetLet 缓动系数是由自己定义的
//外部调用
var oDiv = document.getElementsByTagName('div');
oDiv[0].onmouseover = function(){
startAnimation(this,'width',600)
};
oDiv[0].onmouseout = function(){
startAnimation(this,'width',300)
};
oDiv[1].onmouseover = function(){
startAnimation(this,'height',300)
};
oDiv[1].onmouseout = function(){
startAnimation(this,'height',100)
};
//多值运动函数封装
var speed = 0;
function startAnimation(obj,attr,end) {
//针对于多物体运动,定时器的返回值要绑定在当前的事件中
clearInterval(obj.timer);
obj.timer = setInterval(function () {
//0、获取样式属性
var cur = parseInt(getStyle(obj,attr));
//1、求速度
speed = (end - cur) / 10;
speed = end > cur ? Math.ceil(speed):Math.floor(speed);
//2、临界处理
if(end === cur){
clearInterval(obj.timer);
return;
}
//3、运动起来
obj.style[attr] = cur + speed + 'px';
}, 30);
}
//obj是当前元素对象 attr是当前元素对象的属性
function getStyle(obj, attr) {
if (obj.currentStyle) {
//obj.currentStyle是兼容ie的方法
return obj.currentStyle[attr];
} else {
//主流浏览器的方法
return getComputedStyle(obj, null)[attr];
}
}
}
</script>
</body>
</html>
2、透明度样式处理
在上节课我们留下了一个问题,getStyle函数不可以获取什么属性呢?上节课的代码我们的运动框架逐渐成型,但是这远远还不够,比如看个bug。上节课代码修改
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>10 多值运动透明度的变化</title>
<style>
* {
padding: 0;
margin: 0;
}
div {
width: 300px;
height: 100px;
margin-top: 50px;
background-color: green;
border: 5px solid #000000;
opacity: 0.3;
/* filter: alpha(opacity: 30); */
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
<script>
window.onload = function () {
//1、获取标签
var oDiv = document.getElementsByTagName('div');
oDiv[0].onmouseover = function(){
startAnimation(this,'opacity',100)
};
oDiv[0].onmouseout = function(){
startAnimation(this,'opacity',30)
};
// oDiv[1].onmouseover = function(){
// startAnimation(this,'height',300)
// };
// oDiv[1].onmouseout = function(){
// startAnimation(this,'height',100)
// };
var speed = 0;
function startAnimation(obj,attr,end) {
//针对于多物体运动,定时器的返回值要绑定在当前的事件中
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var cur = 0;
//0、获取样式属性
if(attr === 'opacity'){
//Math.round是对*100之后的数值四舍五入取整
cur = Math.round(parseFloat(getStyle(obj,attr))*100);
}else{
cur = parseFloat(getStyle(obj,attr));
}
//1、求速度
speed = (end - cur) / 10;
speed = end > cur ? Math.ceil(speed):Math.floor(speed);
//2、临界处理
if(end === cur){
clearInterval(obj.timer);
return;
}
//3、运动起来
if(attr === 'opacity'){
obj.style[attr] = (cur + speed)/100 ;
obj.style[attr] =`alpha(opacity: ${cur + speed}) `;
}else{
obj.style[attr] = cur + speed +'px';
}
}, 30);
}
//obj是当前元素对象 attr是当前元素对象的属性
function getStyle(obj, attr) {
if (obj.currentStyle) {
//obj.currentStyle是兼容ie的方法
return obj.currentStyle[attr];
} else {
//主流浏览器的方法
return getComputedStyle(obj, null)[attr];
}
}
}
</script>
</body>
</html>
六、链式动画
物体的多个属性可能是同时运动,也可能是一个属性运动完成之后,另一个属性再运动。如果要完成这种效果,就需要用到回调函数。
如果想实现以上效果。我们现在将封装的运动框架存在一个myAnimation.js文件中。
myAnimation.js
/**
* 动画的函数
* obj 当前的对象
* end 末尾位置
* attr 当前元素对象的属性
*/
//多值运动-函数封装(控制宽、高、及透明度的变化)
var speed = 0;
function startAnimation(obj, attr, end,fn) {
//针对于多物体运动,定时器的返回值要绑定在当前的事件中
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var cur = 0;
//0、获取样式属性
//透明度变化处理,兼容ie和其他主流浏览器
if (attr === 'opacity') {
//由于透明度涉及小数计算,如0.07\*100=> 7.000000000000001,所以需要用Math.round()去掉尾巴*
cur = Math.round(parseFloat(getStyle(obj, attr)) * 100);
} else {
cur = parseFloat(getStyle(obj, attr));
}
//1、求速度
speed = (end - cur) / 10;
speed = end > cur ? Math.ceil(speed) : Math.floor(speed);
//2、临界处理
if (end === cur) {
clearInterval(obj.timer);
//临界点判断(如果有第四个参数则执行,如果没有就直接跳出)
if(fn){
fn();
}
return;
}
//3、运动起来
if (attr === 'opacity') {
obj.style[attr] = (cur + speed) / 100;
obj.style[attr] = `alpha(opacity: ${cur + speed}) `;
} else {
obj.style[attr] = cur + speed + 'px';
}
}, 30);
}
//obj是当前元素对象 attr是当前元素对象的属性
function getStyle(obj, attr) {
if (obj.currentStyle) {
//obj.currentStyle是兼容ie的方法
return obj.currentStyle[attr];
} else {
//主流浏览器的方法
return getComputedStyle(obj, null)[attr];
}
}
外部引用的时候。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>11 链式运动</title>
<style>
* {
padding: 0;
margin: 0;
}
#box{
width: 300px;
height: 100px;
margin-top: 50px;
background-color: green;
border: 5px solid #000000;
/* opacity: 0.3; */
/* filter: alpha(opacity: 30); */
}
</style>
</head>
<body>
<div id="box"></div>
<script src="js/myAnimation.js"></script>
<script>
var box = document.getElementById('box');
box.onmouseover = function(){
startAnimation(box, 'width', 600,function(){
startAnimation(box, 'height', 300)
})
}
</script>
</body>
</html>
七、同时运动的动画
如果之前的运动框架,我们想让元素既可以改变宽度,又可以改变透明度。这个时候我们用到JSON。关于JSON的详细讲解,在后面课程中我们会详细讲解,现在我们先简单用一下
var json = {
"name":"mjj",
"age":29
}
for(var attr in json){
alert(attr);
//获取属性名
alert(json[attr]);
//获取属性值
}
有了上面JSON的简单使用之后,我们将myAnimation.js进行修改。
/**
* 动画的函数(同时运动动画) 利用json实现
* var json = {
"name":"mjj",
"age":29
}
for(var attr in json){
alert(attr);
//获取属性名
alert(json[attr]);
//获取属性值
}
* obj 当前的对象
*/
//多值运动-函数封装(控制宽、高、及透明度的变化)
var speed = 0;
function startAnimation(obj, json, fn) {
//针对于多物体运动,定时器的返回值要绑定在当前的事件中
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var cur = 0;
//标杆 如果flag的值为true,证明说有的属性值都达到终点值
var flag = true;
//0、获取样式属性
for (var attr in json) {
if (attr === 'opacity') {
//由于透明度涉及小数计算,如0.07\*100=> 7.000000000000001,所以需要用Math.round()去掉尾巴*
cur = Math.round(parseFloat(getStyle(obj, attr)) * 100);
} else {
cur = parseFloat(getStyle(obj, attr));
}
//1、求速度
speed = (json[attr] - cur) / 20;
speed = json[attr] > cur ? Math.ceil(speed) : Math.floor(speed);
//2、临界处理
if (json[attr] !== cur) {
flag = false;
}
//3、运动起来
if (attr === 'opacity') {
obj.style[attr] = (cur + speed) / 100;
obj.style[attr] = `alpha(opacity: ${cur + speed}) `;
} else {
obj.style[attr] = cur + speed + 'px';
}
}
if(flag){
clearInterval(obj.timer);
//临界点判断(如果有第四个参数则执行,如果没有就直接跳出)
if (fn) {
fn();
}
return;
}
}, 30);
}
//obj是当前元素对象 attr是当前元素对象的属性
function getStyle(obj, attr) {
if (obj.currentStyle) {
//obj.currentStyle是兼容ie的方法
return obj.currentStyle[attr];
} else {
//主流浏览器的方法
return getComputedStyle(obj, null)[attr];
}
}
外部引用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>11 链式运动</title>
<style>
* {
padding: 0;
margin: 0;
}
#box{
width: 300px;
height: 100px;
margin-top: 50px;
background-color: green;
border: 5px solid #000000;
opacity: 0.3;
/* filter: alpha(opacity: 30); */
}
</style>
</head>
<body>
<div id="box"></div>
<script src="js/myAnimation-2.js"></script>
<script>
var box = document.getElementById('box');
box.onmouseover = function(){
startAnimation(box, {"width":600,"height":300,"opacity":100})
}
box.onmouseout = function(){
startAnimation(box, {"width":300,"height":100,"opacity":30})
}
</script>
</body>
</html>