原生javascript写自己的运动库(匀速运动篇)
网上有很多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写自己的运动库(匀速运动篇)的更多相关文章
- 原生JavaScript写AJAX
前端JavaScript: function ajaxGet(url, obj) { var request; if(window.XMLHttpRequest) { request = new XM ...
- 原生javascript写的侧栏跟随效果
浏览网站时经常看到有的网站上,当一个页面很长的时候,设定侧栏内容会跟随滚动条滚动,我们把这种效果叫做“侧栏跟随滚动”.这种特效对提高网站浏览量.文章点击率.广告点击量都有一定效果. 侧栏跟随滚动的实现 ...
- javascript学习-原生javascript的小特效(原生javascript实现链式运动)
以下代码就不详细解析了,在我之前的多个运动效果中已经解析好多次了,重复的地方这里就不说明了,有兴趣的童鞋可以去看看之前的文章<原生javascript的小特效> <!DOCTYPE ...
- 用原生JavaScript写AJAX
//原生js写ajax就像打电话 //打电话分下面4步//1.拿出手机//2.拨号//3.说话//4.听对方说话 //ajax也分下面4步//1.创建ajax对象//2.连接到服务器//3.发送请求( ...
- 原生JavaScript写select下拉选择后跳转页面
<select name="molsel_oprate" onchange="javascript:var obj = event.target; var inde ...
- 用原生javascript写出jquery中slideUp和slideDown效果
设置块级元素的CSS属性overflow为hidden,然后动态改变height即可 var header=document.getElementsByTagName('header')[0]; he ...
- 自己用原生JS写的轮播图,支持移动端触摸滑动,分页器圆点可以支持mouseover鼠标移入和click点击,高手看了勿喷哈
自己用原生JavaScript写的轮播图,分页器圆点按钮可支持click点击,也可支持mouseover鼠标悬浮触发,同时支持移动端触摸滑动,有兴趣的友友可以试试哈,菜鸟一枚,高手看了勿喷,请多多指正 ...
- 自己用原生JS写的轮播图,支持移动端触屏滑动,面向对象思路。分页器圆点支持click和mouseover。
自己用原生javascript写的轮播图,面向对象思路,支持移动端手指触屏滑动.分页器圆点可以选择click点击或mouseover鼠标移入时触发.图片滚动用的setInterval,感觉setInt ...
- 原生JavaScript运动功能系列(五):定时定点运动
原生JavaScript运动功能系列(一):运动功能剖析与匀速运动实现 原生JavaScript运动功能系列(二):缓冲运动 原生JavaScript运动功能系列(三):多物体多值运动 原生JavaS ...
随机推荐
- c语言和java的区别
今晚读了一下c程序设计语言,这是一本经典书籍,发现C语言和java有很多是相同的,毕竟java是由c语言进化来的. 我大概从我自己的思考来谈谈不同点 1.c语言是面向过程,主要单位是函数,变量和函数的 ...
- 《java入门第一季》之面向对象面试题(fianl关键字)
/* 面试题:final修饰局部变量的问题 基本类型:基本类型的值不能发生改变. 引用类型:引用类型的(地址值)(不能发生改变),但是,该对象的堆内存的值是可以改变的. */ class Studen ...
- CSS中让一个div的高度随着另外个一个统计的div的高度变化而变化的代码
.w1002 .left_part{overflow:hidden; padding-bottom:9999px; margin-bottom:-9999px;display:inline;}
- 青年之锋文学网( www.xcqnzf…
青年之锋文学网( www.xcqnzf.com )简介: 青年之锋文学网创建于2013年秋,是河南农业大学(应用科技学院)--青年之锋文学社的官方网站,网站以长篇写作和出版校刊为主题,短篇精彩丰富为中 ...
- iOS关于蓝牙连接的简单介绍与使用
下面是两台iPhone6连接同一台蓝牙设备的结果: **成功连接**** peripheral: <CBPeripheral: 0x1700f4500, identifier = 50084F6 ...
- node.js 连接数据库
用Nodejs连接MySQL 用Nodejs连接MySQL 从零开始nodejs系列文章 ,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的 ...
- nodejs安装及故障解决
本文来自:http://hxl2009.blog.51cto.com/779549/1031320 给开发搞nodejs环境,遇到点问题记录下过程,备忘. wget http://nodejs.org ...
- 俺的新书《Sencha Touch实战》终于出版了
内容简介:Sencha框架是第一个基于HTML 5的移动也能给予框架,可以让Web应用看起来像网络应用.美丽的用户 界面 组件和丰富的数据管理,全部基于最新的HTML 5和CSS 3的Web标准,全部 ...
- Linux文件系统构成(第二版)
Linux文件系统构成 /boot目录: 内核文件.系统自举程序文件保存位置,存放了系统当前的内核[一般128M即可] 如:引导文件grub的配置文件等 /etc目录: 系统常用的配置文件,所以备份系 ...
- 在Windows使用git工具将代码同步至github(作者:ying1989920)
[ps]git是一个分布式代码管理工具,类似于svn,方便协同开发,git里面有所谓的仓库(用来存放代码的),分为本地和线上,线上的你可以自己搭建,不想搭建的话github就给你提供了. [关于 ...