网上有很多JavaScript的运动库,这里和大家分享一下用原生JavaScript一步一步写一个运动函数的过程,如读者有更好的建议欢迎联系作者帮助优化完善代码。这个运动函数完成后,就可以用这个运动函数写轮播、选项卡、滚动文字的特效。运动的模式有很多,如匀速运动、匀加速运动、变加速运动等等。这里我们以匀速运动为例。

现在我们先用HTML和CSS将我们的运动对象建好

 <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>move</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style type="text/css">
.box1{width:100px; height: 100px; background: red; position: absolute; left: 0px; top:50px;opacity:1; filter: alpha(opacity=100);}
span{display: block; width:1px; height:300px; background:black; position: absolute; left: 500px; top: 0;}
</style>
</head>
<body>
<div class="box1"></div>
<span></span>
</body>
</html>

打开浏览器会看到一个红色的块,和一条黑色的线,现在我们要让红色的左边线移动到黑线处。那么怎么移动过去呢?如果用老式电影播放机看过电影,应该知道我们看的电影实际上是有一张张的图片组成的,这些图片播放的速度很多也就成了一组连续的动作。我们这里的运动函数也是基于这种原理。

我们先获取当前left的位置,然后设定一个定时器,定时器执行一次left加10个像素,这样红色部分就可以向右运动了。这里我们设置定时器16毫秒执行一次,也就相当于1秒钟执行62.5次,大概就是60帧。在执行left加10个像素前我们还要进行一个判断用来判断何时关定时器。判断条件是如果当前left到目标点的距离小于10就关闭定时器,并让left的值等于目标值。

现在开始写JavaScript运动函数

 window.onload = function(){
var oDiv = document.getElementsByTagName('div')[0];
oDiv.onclick = function(){
startMove();
}
}
var timer = null;
function startMove(target){
//获取运动目标
var oDiv = document.getElementsByTagName('div')[0];
timer = setInterval(function(){
//如果当前left到目标点的距离(500)小于10就关闭定时器;
if(500-oDiv.offsetLeft<10){
clearInterval(timer)
oDiv.style.left = 500 + 'px';
}else{
oDiv.style.left = oDiv.offsetLeft + 10 + 'px';
}
}, 16);
}

这样我们就可以完成了一个向右运动的过程,但是不完美,只能向右运动(这里的10如果是-10就可以向左运动),只能运动到函数内指定的位置(即目标值),我们用speed来替换10,用target替换500,target由函数参数传入。speed=(目标值-当前值)/60,这里的60相当于是每秒60帧。目标值>当前值,speed就是一个正数,当前值向目标值靠近;目标值<当前值,speed就是一个负数,当前值也是向目标值靠近。我们用于判断的条件换成绝对值比较。

优化后的代码

 window.onload = function(){
var oDiv = document.getElementsByTagName('div')[0];
oDiv.onclick = function(){
startMove(500);
}
}
var timer = null;
function startMove(target){
//获取运动目标
var oDiv = document.getElementsByTagName('div')[0];
var speed = (target-oDiv.offsetLeft)/60;
timer = setInterval(function(){
//如果当前left到目标点的距离(target)小于speed就关闭定时器;
if(Math.abs(target-oDiv.offsetLeft)<Math.abs(speed)){
clearInterval(timer)
oDiv.style.left = target + 'px';
}else{
oDiv.style.left = oDiv.offsetLeft + speed + 'px';
}
}, 16);
}

测试div的left为0或者1000的时候,都运动到了目标位置500,但是还是不完美,只能移动left,如果要移动top还得改函数内部的left,这里我们将移动属性也作为参数传入函数。offsetLeft也换个形式,我们引入一个获取对象属性值的函数

 window.onload = function(){
var oDiv = document.getElementsByTagName('div')[0];
oDiv.onclick = function(){
startMove('top', 500); }
} //获取对象属性值
function getStyle(obj, attr){
if(window.getComputedStyle){
return window.getComputedStyle(obj, false)[attr];
}else{
return obj.currentStyle[attr];
}
}
var timer = null; //运动函数
function startMove(attr, target){
//获取运动目标
var oDiv = document.getElementsByTagName('div')[0];
var speed = (target-parseFloat(getStyle(oDiv, attr)))/60; timer = setInterval(function(){
var fCur = parseFloat(getStyle(oDiv, attr));
//如果当前位置到目标点的距离,小于speed就关闭定时器;
if(Math.abs(target-fCur)<Math.abs(speed)){
clearInterval(timer)
oDiv.style[attr] = target + 'px';
}else{
oDiv.style[attr] = fCur + speed + 'px';
} }, 16);
}

现在我们已经可以做多个属性值的运动了,但是还是有bug,运行下列代码试试

 window.onload = function(){
var oDiv = document.getElementsByTagName('div')[0];
oDiv.onmouseover = function(){
startMove('width', 500);
}
oDiv.onmouseout = function(){
startMove('width', 100);
}
}

你会发现有时不受控制,这是因为我们对同一个对象开了多个定时运动导致的,我们再加一行代码clearInterval(timer);加在timer = setInterval()之前,在每个运动的定时器开启前去除其他的定时器,这样问题就解决了。但是还是不完美,只能一个对象运动,现在我要让多个对象运动,就不行,那是因为运动对象在我们的函数里,现在我们将运动对象也作为参数传进函数。

 <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>move</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style type="text/css">
.box1{width:100px; height: 50px; background: red; position: absolute; left: 0px; top: 0px;opacity:1; filter: alpha(opacity=100);/* border: 1px solid black;*/}
.box2{width:100px; height: 50px; background: red; position: absolute; left: 0; top: 80px;}
.box3{width:100px; height: 50px; background: red; position: absolute; left: 0; top: 160px;}
span{display: block; width:1px; height:300px; background:black; position: absolute; left: 500px; top: 0;}
</style>
</head>
<body>
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
<span></span>
</body>
</html>

html修改测试多物体运动

 window.onload = function(){
var oDiv = document.getElementsByTagName('div');
oDiv[0].onmouseover = function(){
startMove(this, 'width', 500);
}
oDiv[0].onmouseout = function(){
startMove(this, 'width', 100);
}
oDiv[1].onmouseover = function(){
startMove(this, 'width', 500);
}
oDiv[1].onmouseout = function(){
startMove(this, 'width', 100);
}
oDiv[2].onmouseover = function(){
startMove(this, 'width', 500);
}
oDiv[2].onmouseout = function(){
startMove(this, 'width', 100);
}
} //获取对象属性值
function getStyle(obj, attr){
if(window.getComputedStyle){
return window.getComputedStyle(obj, false)[attr];
}else{
return obj.currentStyle[attr];
}
} //运动函数
function startMove(obj, attr, target){
var speed = (target-parseFloat(getStyle(obj, attr)))/60;
clearInterval(obj.timer); obj.timer = setInterval(function(){
var fCur = parseFloat(getStyle(obj, attr));
//如果当前位置到目标点的距离,小于speed就关闭定时器;
if(Math.abs(target-fCur)<Math.abs(speed)){
clearInterval(obj.timer)
obj.style[attr] = target + 'px';
}else{
obj.style[attr] = fCur + speed + 'px';
} }, 16);
}

现在可以进行多物体的运动了,但是一个物体运动时其他物体就停止了运动,那是因为多个物体公用一个定时器导致的,我们再对代码进行改进,给每个对象添加属于自己的定时器。

即把startMove函数里的所有timer改成obj.timer就可以进行多个物体同时运动了。但是还是不完美,一个对象一次只能运动一个属性,不能同时改变多个属性,现在我们将startMove的参数attr和target用json数据对象传入。代码修改如下:

 window.onload = function(){
var oDiv = document.getElementsByTagName('div');
//测试一个对象同时运动对个属性
oDiv[0].onclick = function(){
startMove(this, {'width':50, 'left':500, 'height':200, 'top':100});
}
} //获取对象属性值
function getStyle(obj, attr){
if(window.getComputedStyle){
return window.getComputedStyle(obj, false)[attr];
}else{
return obj.currentStyle[attr];
}
} //运动函数
function startMove(obj, json){
var speed = {};
//给每个属性设一个速度
for (var attr in json){
speed[attr] = (json[attr]-parseFloat(getStyle(obj, attr)))/60;
}
clearInterval(obj.timer);attr obj.timer = setInterval(function(){
var fCur = 0;
var btn = true;
for(var attr in json){
fCur = parseFloat(getStyle(obj, attr));
//判断运动的完成条件,
if(Math.abs(fCur-json[attr])<Math.abs(speed[attr])){
btn = false;
}
obj.style[attr] = fCur + speed[attr] + 'px';
}
//因为速度是根据(目标值-当前值)/60来确定的,所以每个属性的完成时间是一样的
//在运动完成时给所以属性值设置为目标值,并清楚定时器。
if(btn == false){
for(var attr in json){
obj.style[attr] = json[attr] + 'px';
}
clearInterval(obj.timer);
} }, 16);
}

到现在,一个运动函数基本完成了,但还有优化的地方。可以给函数增加一个参数,参数是一个函数,即要求运动完成后执行一个函数。另外我们的运动函数不能修改透明度,我们对透明度单独处理,实现透明度的修改就可以做淡入谈出了。如果还想控制运动的快慢可以在参数json中增加一个时间参数,为了框架的通用性,稍微有一点点复杂,这也是为了框架可以应对更多的需求。现在来修改我们的运动函数,使它可以完成上述三个功能。

 window.onload = function(){
var oDiv = document.getElementsByTagName('div');
//测试一个对象同时运动对个属性
oDiv[0].onclick = function(){
startMove(this, {'width':50, 'left':500,'time':3000, 'opacity':0.3, 'height':200, 'top':100}, function(){
startMove(oDiv[0], {'width':200, 'left':1000, 'opacity':1, 'height':50, 'top':0})
});
}
} //获取对象属性值
function getStyle(obj, attr){
if(window.getComputedStyle){
return window.getComputedStyle(obj, false)[attr];
}else{
return obj.currentStyle[attr];
}
} //运动函数
function startMove(obj, json, fun){
//设置默认的运动频率
var iFrame = 60;
var velocity = {};
//判断时候有时间属性,有就设置用户iFrame
if (json['time']){
iFrame = parseInt(json['time'])/16;
}
//删除时间属性
delete json['time']
//给每个属性设一个速度
for (var attr in json){
velocity[attr] = (json[attr]-parseFloat(getStyle(obj, attr)))/iFrame;
} clearInterval(obj.timer);attr
//开启定时器,开始运动
obj.timer = setInterval(function(){
var fCur = 0;
var btn = true;
for(var attr in json){
//获取当前属性值
fCur = parseFloat(getStyle(obj, attr));
//判断运动的完成条件,
if(Math.abs(fCur-json[attr])<Math.abs(velocity[attr])){
btn = false;
}
//判断attr如果是opacity则执行透明度变化的代码,否则执行其他属性值变化代码
if(attr=='opacity'){
obj.style[attr] = fCur + velocity[attr];
obj.style.filter = 'alpha(opacity=' + (fCur + velocity[attr])*100 + ')';
}else{
obj.style[attr] = fCur + velocity[attr] + 'px';
}
}
//因为速度是根据(目标值-当前值)/60来确定的,所以每个属性的完成时间是一样的
//在运动完成时给所以属性值设置为目标值,并清楚定时器。
if(btn == false){
for(var attr in json){
if(attr=='opacity'){
obj.style[attr] = json[attr];
obj.style.filter = 'alpha(opacity=' + (json[attr])*100 + ')';
}else{
obj.style[attr] = json[attr] + 'px';
}
}
//清楚定时器,并判断是否执行函数
clearInterval(obj.timer);
if(fun){
fun();
}
}
}, 16);
}

这样我们的匀速运动函数就完成了,有了它就可以写轮播、文字滚动等运动特效了。后期会增加变速运动部分,读者也可自行修改代码,使其可以做变速运动。现将我们最终版的匀速运动函数提取出来放在一个单独的js文件中,这样以后直接在html文件中导入就行了。将函数名startMove改成uniformMotion(匀速运动),js文件名为motion.js

 //获取对象属性值
function getStyle(obj, attr){
if(window.getComputedStyle){
return window.getComputedStyle(obj, false)[attr];
}else{
return obj.currentStyle[attr];
}
} //运动函数
function uniformMotion(obj, json, fun){
//设置默认的运动频率
var iFrame = 60;
var velocity = {};
//判断时候有时间属性,有就设置用户iFrame
if (json['time']){
iFrame = parseInt(json['time'])/16;
}
//删除时间属性
delete json['time']
//给每个属性设一个速度
for (var attr in json){
velocity[attr] = (json[attr]-parseFloat(getStyle(obj, attr)))/iFrame;
} clearInterval(obj.timer);attr
//开启定时器,开始运动
obj.timer = setInterval(function(){
var fCur = 0;
var btn = true;
for(var attr in json){
//获取当前属性值
fCur = parseFloat(getStyle(obj, attr));
//判断运动的完成条件,
if(Math.abs(fCur-json[attr])<Math.abs(velocity[attr])){
btn = false;
}
//判断attr如果是opacity则执行透明度变化的代码,否则执行其他属性值变化代码
if(attr=='opacity'){
obj.style[attr] = fCur + velocity[attr];
obj.style.filter = 'alpha(opacity=' + (fCur + velocity[attr])*100 + ')';
}else{
obj.style[attr] = fCur + velocity[attr] + 'px';
}
}
//因为速度是根据(目标值-当前值)/60来确定的,所以每个属性的完成时间是一样的
//在运动完成时给所以属性值设置为目标值,并清楚定时器。
if(btn == false){
for(var attr in json){
if(attr=='opacity'){
obj.style[attr] = json[attr];
obj.style.filter = 'alpha(opacity=' + (json[attr])*100 + ')';
}else{
obj.style[attr] = json[attr] + 'px';
}
}
//清楚定时器,并判断是否执行函数
clearInterval(obj.timer);
if(fun){
fun();
}
}
}, 16);
}

成功的背后离不开辛勤的付出。

原生javascript写自己的运动库(匀速运动篇)的更多相关文章

  1. 原生JavaScript写AJAX

    前端JavaScript: function ajaxGet(url, obj) { var request; if(window.XMLHttpRequest) { request = new XM ...

  2. 原生javascript写的侧栏跟随效果

    浏览网站时经常看到有的网站上,当一个页面很长的时候,设定侧栏内容会跟随滚动条滚动,我们把这种效果叫做“侧栏跟随滚动”.这种特效对提高网站浏览量.文章点击率.广告点击量都有一定效果. 侧栏跟随滚动的实现 ...

  3. javascript学习-原生javascript的小特效(原生javascript实现链式运动)

    以下代码就不详细解析了,在我之前的多个运动效果中已经解析好多次了,重复的地方这里就不说明了,有兴趣的童鞋可以去看看之前的文章<原生javascript的小特效> <!DOCTYPE ...

  4. 用原生JavaScript写AJAX

    //原生js写ajax就像打电话 //打电话分下面4步//1.拿出手机//2.拨号//3.说话//4.听对方说话 //ajax也分下面4步//1.创建ajax对象//2.连接到服务器//3.发送请求( ...

  5. 原生JavaScript写select下拉选择后跳转页面

    <select name="molsel_oprate" onchange="javascript:var obj = event.target; var inde ...

  6. 用原生javascript写出jquery中slideUp和slideDown效果

    设置块级元素的CSS属性overflow为hidden,然后动态改变height即可 var header=document.getElementsByTagName('header')[0]; he ...

  7. 自己用原生JS写的轮播图,支持移动端触摸滑动,分页器圆点可以支持mouseover鼠标移入和click点击,高手看了勿喷哈

    自己用原生JavaScript写的轮播图,分页器圆点按钮可支持click点击,也可支持mouseover鼠标悬浮触发,同时支持移动端触摸滑动,有兴趣的友友可以试试哈,菜鸟一枚,高手看了勿喷,请多多指正 ...

  8. 自己用原生JS写的轮播图,支持移动端触屏滑动,面向对象思路。分页器圆点支持click和mouseover。

    自己用原生javascript写的轮播图,面向对象思路,支持移动端手指触屏滑动.分页器圆点可以选择click点击或mouseover鼠标移入时触发.图片滚动用的setInterval,感觉setInt ...

  9. 原生JavaScript运动功能系列(五):定时定点运动

    原生JavaScript运动功能系列(一):运动功能剖析与匀速运动实现 原生JavaScript运动功能系列(二):缓冲运动 原生JavaScript运动功能系列(三):多物体多值运动 原生JavaS ...

随机推荐

  1. 新手自定义view练习实例之(二) 波浪view

    本系列是为新手准备的自定义view练习项目(大牛请无视),相信在学习过程中,想学自定义view又无从下手,不知道做什么.本系列为新手提供了一系列自定义view的简单实例.看过理解之后,自己实现,相信会 ...

  2. How tomcat works 读书笔记十五 Digester库 下

    在这一节里我们说说ContextConfig这个类. 这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的co ...

  3. javascript、ruby和C性能一瞥(3) :上汇编

    在博文(1)和(2)里分别用了4中方式写一个素数筛选的算法,分别是javascript in browser.node.js.ruby和c:最终的结果是c最快,node.js其次,js in b虽然也 ...

  4. leetCode之旅(14)-Number of 1 Bits

    题目描述: Write a function that takes an unsigned integer and returns the number of '1' bits it has (als ...

  5. The 1st tip of DB Query Analyzer

     The 1st tip of DB Query Analyzer               Ma Genfeng   (Guangdong Unitoll Services incorporate ...

  6. VueJs(8)---组件(注册组件)

    组件(注册组件) 一.介绍 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树 那么什么是组件呢? 组 ...

  7. JavaScript 对象分类

    参考自W3School:JavaScript对象主要有三类. 一:JavaScript核心对象是ECMAScript标准定义好的一些对象与函数,在JavaScript语言中可以直接使用.主要常用有如下 ...

  8. javaScript(4)---数据类型

    javaScript(4)---数据类型 第4章 数据类型 学习要点: 1.typeof操作符 2.Undefined类型 3.Null类型 4.Boolean类型 5.Number类型 6.Stri ...

  9. win8 JDK环境变量不生效

    执行where java  看一下路径对不对,如果对的话就把system32下面的3个java相关的exe删了即可,如果路径不对就修改环境变量.

  10. Linux的vi详解

    Vi简介1. Vi是一种广泛存在于各种UNIX和Linux系统中的文本编辑程序.2. Vi不是排版程序,只是一个纯粹的文本编辑程序.3. Vi是全屏幕文本编辑器,它没有菜单,只有命令.4. Vi不是基 ...