首先来看最基础的运动:单个物体向右匀速运动到某一点停止

     例子:一个按钮,一个div,点击按钮,让div向右运动到某一个位置暂停

  1. // 原理: 1 获取物体当前的位置 oDiv.offsetleft
  2. // 2 利用定时器,每隔一定的时间,让物体位置增加相同的距离(10px)。
  3. // 3 判断物体是否移动到指定位置(500px),如果到达,就清除定时器
  4.  
  5. var oBtn = document.getElementById('btn');
  6. var oDiv = document.getElementById('div1');
  7. var iTimer = null;
  8. oBtn.onclick = function() {
  9. iTimer = setInterval(function() {
  10. if (oDiv.offsetLeft == 500) {
  11. clearInterval(iTimer);
  12. } else {
  13. oDiv.style.left = oDiv.offsetLeft + 10 + 'px';
  14. }
  15.  
  16. }, 30);
  17. }
  18.  
  19. // 存在问题: 1 当我们一直不停的点按钮的时候,物体运动速度会加快。
  20. // 原因:我们每点击一次按钮,就会开启一个定时器,有时候上次定时器还没清除, 这个就开启了,当多个定时器一起物体运动就会加快。
  21. // 解决: 在点击按钮的时候,先清除上次的定时器。保证运动中,只有一个定时器在执行。
  22. // 2 当我们指定的位置不是500,是别的位置的时候,有可能物体停不下来。
  23. // 原因:物体每次向前移动10px,不一定就正好到我们指定的位置,除非这个数字刚好整 除每次移动的距离。其实也不算是个问题,但是个需要注意的点。
  24. // 解决:在作条件判断的时候,判断范围,而不是指定的位置。(oDiv.offsetLeft >= 500)

所以我们可以知道运动需要注意:1 运动前清除上次定时器

2 开启定时器,指向运动

3  运动中指定运动的形式(匀速缓存还是什么的),并且加入条件判断,以便停止

封装函数:对于以上运动的改进代码,我就不做具体的示范了,我们直接来进行简单的封装。在封装函数中顺便改进上面的函数了。

  1. var oBtn = document.getElementById('btn');
  2. var oDiv = document.getElementById('div1');
  3. var iTimer = null;
  4. oBtn.onclick = function() {
  5. startMove();
  6. }
  7.  
  8. // 封装后的函数
  9. function startMove() {
  10. clearInterval(iTimer); //运动前清除定时器
  11. iTimer = setInterval(function() {
  12. if (oDiv.offsetLeft == 500) {
  13. clearInterval(iTimer); //满足条件清除定时器
  14. } else {
  15. oDiv.style.left = oDiv.offsetLeft + 10 + 'px'; //每次向前移动
  16. }
  17.  
  18. }, 30);
  19. }

扩展需求1:根据上面的函数我们可以实现,一个物体向右运动到某一个位置。那么我们现在如果有两个物体,一个向左运动,一个向右运动,且运动的目的地是不同的,那么上面的函数是不是就不满足了呢?

改进:多物体多方向运动

  1. // 函数封装原则: 1 不变的不动
  2. // 2 改变的东西作为参数
  3. // 3 改变太多的进行条件判断
  4.  
  5. // 改变的是运动的物体(obj)运动方向(iSpeed)和运动的目标(iTarget) ,如下作为参数
  6.  
  7. oDiv1.onmouseover = function() {
  8. startMove(this,0, 10);
  9. }
  10. oDiv1.onmouseout = function() {
  11. startMove(this,-100, -10);
  12. }
  13.  
  14. function startMove(obj, iTarget, iSpeed) {
  15. clearInterval(iTimer);
  16.  
  17. iTimer = setInterval(function() {
  18.  
  19. if (obj.offsetLeft == iTarget) {
  20. clearInterval(iTimer);
  21. } else {
  22. obj.style.left = obj.offsetLeft + iSpeed + 'px';
  23. }
  24.  
  25. }, 30);
  26. }

扩大需求2:现在我们不仅仅改变的是物体左右移动,我们想让一个物体的透明度也能改变。能作出淡入淡出的效果。

存在的问题是

问题1 : 在css中,不同浏览器对透明度的设置方式不同。

  1. IE filter: alpha(opacity=30);(0-100
  2. 其他: opacity: 0.3;(0-1
  3. // 所以存在的问题是:用哪种方式来判断透明度是否到达我们所指定的目标,是用0-1,还是0-100来判断呢?
  4.  
  5. 在这里要普及一个知识
  6. alert(0.1+0.2) // 0.30000004
  7. alert(0.2+0.7) // 0.89999999
  8.  
  9. // 看上面的代码,会发现并没有像我们想象中弹出0.3,和0.9,是因为在JS中对于小数//的计算结果,是近似值。所以我们用0-100判断更加准确。

问题2 :如何获取到物体的透明度,用obj.style.opacity 吗?

这里要说明一个知识点,在JS中用style只能获取行间样式。 不能获取css中的样式。这个时候我们用什么呢?下面的两个方法可以获取非行间样式,有兼容问题:

1  getComputedStyle: getComputedStyle(element,随意值(写什么都可以,比如false)).attr:这个获取的是计算机计算后的样式,不能获取复合样式,只有标准浏览器支持IE6 7 8不兼容。

2  currentStyle :currentStyle[attr],只有IE6 7 8兼容 ,可以获取非行间样式,还可以获取自定义样式。

所以需要做一下兼容,我们可以封装成一个函数,如下:

  1. function getStyle ( obj, attr ) {
  2.  
  3. if(obj.currentStyle){
  4. obj.currentStyle[attr]
  5. }else{
  6. getComputedStyle( obj )[attr];
  7. }
  8.  
  9. }
  10.  
  11. //简写方式
  12. function getStyle ( obj, attr ) {
  13.  
  14. return obj.currentStyle?obj.currentStyle[attr] : getComputedStyle( obj )[attr];
  15.  
  16. }
  17.  
  18. //注意 IE下虽然没有opacity,但也能获取到opacity值,主要是因为currentStyle的原因,它能读取到任何样式的值,哪怕不存在

所以对于透明度的改变,我们可以封装成如下的函数:

  1. function startMove2(obj, iTarget, iSpeed) {
  2. clearInterval(iTimer);
  3. var iCur = 0; //用来存放当前的透明度值
  4. iTimer = setInterval(function() {
  5. // iCur = getStyle( obj, 'opacity' ) * 100; // 因为getStyle取出来的是小数,乘以100, 是29.999900000045 这样的数,这样我们无法和iTarget进行判断,所以我们可以进行四舍五入,如下:
  6. iCur = Math.round(getStyle( obj, 'opacity' ) * 100);
  7. if (iCur == iTarget) {
  8. clearInterval(iTimer);
  9. } else { //对不同的浏览器进行分别处理
  10. obj.style.opacity = (iCur + iSpeed) / 100;
  11. obj.style.filter = 'alpha(opacity='+ (iCur + iSpeed) +')';
  12. }
  13. }, 30);
  14. }

这只是改变透明度的函数封装,要是能把透明度的封装函数和前面的运动封装函数,结合起来,不就能封装成一个可以改变透明度,也可以改变位置的函数了吗。。。。

那么依照我们的合并原则,找出两个封装函数的不同之处:

运动的属性不同(attr)

2 因为不同的属性处理不同,其实主要是透明度处理是有差别的,其他宽高改变位置改变其实都一样)这个时候的差别,可以采用判断来解决

  1. // 还解决了解决了一个问题是因为之前只有一个定时器,现在因为有多个属性可以运动了,所以就不能只用一个定时器了去控制了,每个物体运动的时候就应该有自己的定时器,所以就把定时器就用obj.timer上,这样每个物体都不同啦。
  2.  
  3. function startMove(obj, attr, iTarget, iSpeed) {
  4. clearInterval(obj.iTimer);
  5. var iCur = 0;
  6.  
  7. obj.iTimer = setInterval(function() {
  8. //对透明度进行判断如果是就进行上面的处理,不是就进行下面的处理
  9. if (attr == 'opacity') {
  10. iCur = Math.round(getStyle( obj, 'opacity' ) * 100);
  11. } else {
  12. iCur = parseInt(getStyle(obj, attr));
  13. }
  14.  
  15. if (iCur == iTarget) {
  16. clearInterval(obj.iTimer);
  17. } else {
  18. if (attr == 'opacity') {
  19. obj.style.opacity = (iCur + iSpeed) / 100;
  20. obj.style.filter = 'alpha(opacity='+ (iCur + iSpeed) +')';
  21. } else {
  22. obj.style[attr] = iCur + iSpeed + 'px';
  23. }
  24. }
  25.  
  26. }, 30);
  27. }
  28.  
  29. function getStyle(obj, attr) {
  30. if (obj.currentStyle) {
  31. return obj.currentStyle[attr];
  32. } else {
  33. return getComputedStyle(obj, false)[attr];
  34. }
  35. }

不过上面的函数,还是不能满足某些需求,比如我想要一个物体的两个属性同时运动,下面这样是实现不了的。

  1. //下面的运动会清除掉上面的定时器
  2.  
  3. startMove(this, 'width', 200, 10);
  4. startMove(this, 'height', 200, 10);

那么怎么样实现这两个属性可以同时运动呢?这个时候我们可以考虑用json的格式

  1. oDiv1.onclick = function() {
  2. startMove(this, {
  3. width : 200,
  4. height: 300
  5. }, 10);
  6. }
  7. function startMove(obj, json, iSpeed) {
  8. clearInterval(obj.iTimer);
  9. var iCur = 0;
  10.  
  11. obj.iTimer = setInterval(function() {
  12. //定时器每走一下就要把要运动的属性都推进一次
  13.  
  14. for ( var attr in json ) {
  15.  
  16. var iTarget = json[attr];//把我们传进来的属性值赋给目标值
  17.  
  18. if (attr == 'opacity') {
  19. iCur = Math.round(getStyle( obj, 'opacity' ) * 100);
  20. } else {
  21. iCur = parseInt(getStyle(obj, attr));
  22. }
  23.  
  24. if (iCur == iTarget) {
  25. clearInterval(obj.iTimer);
  26. } else {
  27. if (attr == 'opacity') {
  28. obj.style.opacity = (iCur + iSpeed) / 100;
  29. obj.style.filter = 'alpha(opacity='+ (iCur + iSpeed) +')';
  30. } else {
  31. obj.style[attr] = iCur + iSpeed + 'px';
  32. }
  33. }
  34.  
  35. }
  36.  
  37. }, 30);
  38. }
  39.  
  40. function getStyle(obj, attr) {
  41. if (obj.currentStyle) {
  42. return obj.currentStyle[attr];
  43. } else {
  44. return getComputedStyle(obj, false)[attr];
  45. }
  46. }

存在问题:上面的运动速度都是一样的,但是传进去的目标点是不一样的,这个时候就会有一个属性先到,那么运动就终止了。所以我们需要解决的是,当所有的属性都到达了目标点,才让运动终止。

解决:定义一个开关,每次运动前假设它是真的,在运动中,只要有一个属性没运动到终点,就把开关变成假,在循环外面进行判断,当所有属性都运动到终点了,开关肯定都是真的,就会清除定时器了。

  1. oDiv1.onclick = function() {
  2. startMove(this, {
  3. width : 200,
  4. height: 300
  5. }, 10);
  6. }
  7. function startMove(obj, json, iSpeed) {
  8. clearInterval(obj.iTimer);
  9. var iCur = 0;
  10.  
  11. obj.iTimer = setInterval(function() {
  12. //定时器每走一下就要把要运动的属性都推进一次
  13. var iBtn = true;//每一次运动前都初始化为真,就是假设所有属性都到了
  14.  
  15. for ( var attr in json ) {
  16.  
  17. var iTarget = json[attr];//把我们传进来的属性值赋给目标值
  18.  
  19. if (attr == 'opacity') {
  20. iCur = Math.round(getStyle( obj, 'opacity' ) * 100);
  21. } else {
  22. iCur = parseInt(getStyle(obj, attr));
  23. }
  24.  
  25. if (iCur != iTarget) {
  26. iBtn = false; //如果有一个属性没到,就把这个开关变成假if (attr == 'opacity') {
  27. obj.style.opacity = (iCur + iSpeed) / 100;
  28. obj.style.filter = 'alpha(opacity='+ (iCur + iSpeed) +')';
  29. } else {
  30. obj.style[attr] = iCur + iSpeed + 'px';
  31. }
  32. }
  33.  
  34. }
  35. //在这里来看下,所有属性是不是都到了目标点,当这里变真的了,说明所有属性都到了目标点,就可以清除定时器了
  36. if (iBtn) {
  37. clearInterval(obj.iTimer);
  38. }
  39.  
  40. }, 30);
  41. }
  42.  
  43. function getStyle(obj, attr) {
  44. if (obj.currentStyle) {
  45. return obj.currentStyle[attr];
  46. } else {
  47. return getComputedStyle(obj, false)[attr];
  48. }
  49. }

扩大需求:假如我们这次实现的不是多个属性同时运动,我希望先把高改变,接着再改变宽,这个时候,我们需要的就是个回调函数了(fn)。za

  1. oDiv1.onclick = function() {
  2.  
  3. startMove(this, {
  4. width : 200
  5. }, 10, function() {
  6. startMove(this, {
  7. height : 200
  8. }, 10);
  9. });
  10. }
  11.  
  12. function startMove(obj, json, iSpeed, fn) {
  13. clearInterval(obj.iTimer);
  14. var iCur = 0;
  15.  
  16. obj.iTimer = setInterval(function() {
  17.  
  18. var iBtn = true;
  19.  
  20. for ( var attr in json ) {
  21.  
  22. var iTarget = json[attr];
  23.  
  24. if (attr == 'opacity') {
  25. iCur = Math.round(getStyle( obj, 'opacity' ) * 100);
  26. } else {
  27. iCur = parseInt(getStyle(obj, attr));
  28. }
  29.  
  30. if (iCur != iTarget) {
  31. iBtn = false;
  32. if (attr == 'opacity') {
  33. obj.style.opacity = (iCur + iSpeed) / 100;
  34. obj.style.filter = 'alpha(opacity='+ (iCur + iSpeed) +')';
  35. } else {
  36. obj.style[attr] = iCur + iSpeed + 'px';
  37. }
  38. }
  39.  
  40. }
  41.  
  42. if (iBtn) {
  43. clearInterval(obj.iTimer);
  44. fn && fn.call(obj); //如果回调函数存在再执行,call方向为了修正this的指向,之前关于this文章有讲过这个用法。
  1. }
  2.  
  3. }, 30);
  4. }
  5.  
  6. function getStyle(obj, attr) {
  7. if (obj.currentStyle) {
  8. return obj.currentStyle[attr];
  9. } else {
  10. return getComputedStyle(obj, false)[attr];
  11. }
  12. }

JS运动从入门到精髓!哈哈的更多相关文章

  1. JS运动从入门到兴奋1

    hello,我是沐晴,一个充满了才华,却靠了照骗走江湖的前端妹子.在这个充满PS的年代,这你们都信,哈哈,废话不多说,今天要分享的是关注JS运动的知识.楼主一直认为,不管学习什么,核心思想才是王道,掌 ...

  2. 带无缝滚动的轮播图(含JS运动框架)

    今天学习了一下轮播图的写作,想到前一阵学过的无缝滚动得思想,所以就把轮播与滚动结合了一下.不过我的代码的神逻辑我自己都不敢恭维,在没网没参照的情况下,只能硬着头皮往下写,希望跟大家共勉吧. js运动框 ...

  3. js运动框架之一条乱跑的虫子

    克隆与运动框架的联合应用 效果:点击元素块后,元素块开始随机的向任何方向移动,并附带一堆颜色随机的"尾巴".每个方向运动3秒后改变方向,同时笑脸变哭脸. 如图所示: 朝某个方向运动 ...

  4. 关于js运动的一些总结

    js运动实现,有两种.一种是速度版,另一种是时间版. 速度版是通过对速度的加减乘除,得出元素的运动数据.时间版是通过对时间进行Tween公式运算,得出元素的运动数据. 速度版运动优点:容易在运动过程中 ...

  5. JS运动学习笔记 -- 任意值的运动框架(高/宽度,背景颜色,文本内容,透明度等)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. js运动动画

    原文:js运动动画 今天简单的学了一下js运动动画,再此感谢慕课网的这位老师http://www.imooc.com/view/167,讲的很不错. 下面是我整理出来的结果. 知识点一:速度动画. 1 ...

  7. Vue (一) --- vue.js的快速入门使用

    =-----------------------------------把现在的工作做好,才能幻想将来的事情,专注于眼前的事情,对于尚未发生的事情而陷入无休止的忧虑之中,对事情毫无帮助,反而为自己凭添 ...

  8. Node.js API快速入门

    Node.js API 快速入门 一.事件EventEmitter const EventEmitter = require('events'); class MyEmitter extends Ev ...

  9. 第八节 JS运动基础

    运动基础 让Div运动起来 速度——物体运动的快慢 运动中的Bug 不会停止 速度取某些值会无法停止 到达位置后再点击还会运动 重复点击速度加快 匀速运动(速度不变) 运动框架及应用: 运动框架: 在 ...

随机推荐

  1. PHP过滤外部链接及外部图片 添加rel="nofollow"属性

    原来站内很多文章都是摘录的外部文章,文章里很多链接要么是时间久了失效了,要么就是一些测试的网址,如:http://localhost/ 之类的,链接多了的话,就形成站内很多死链接,这对SEO优化是很不 ...

  2. Solr安装入门、查询详解

    Solr安装入门:http://www.importnew.com/12607.html 查询详解:http://www.360doc.com/content/14/0306/18/203871_35 ...

  3. OC基础--Hello Shit

    /*  Foundation.h为主头文件, 主头文件中又拷贝了该工具箱中所有工具的头文件, 我们只需要导入主头文件就可以使用该工具箱中所有的工具, 避免了每次使用都要导入一个对应的头文件  工具箱的 ...

  4. select document library from certain list 分类: Sharepoint 2015-07-05 07:52 6人阅读 评论(0) 收藏

    S using System; using Microsoft.SharePoint; namespace Test { class ConsoleApp { static void Main(str ...

  5. java 内存机制简介

    java内存回收机制 不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址.java中对象是采用new或者反射的方法创 建的,这些对象的创建都是在堆中分配,所 ...

  6. SQL实践中的50句

    一个项目涉及到的50个Sql语句(整理版)--1.学生表Student(S,Sname,Sage,Ssex) --S 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别--2.课程 ...

  7. Android使用文件存储数据

    Android上最基本的存储数据的方式即为使用文件存储数据,使用基本的Java的FileOutStream,BufferedWriter,FileInputStream和BufferedReader即 ...

  8. SPOJ BALNUM

    一开始题看错了...dp[pos][sets][viss],其中sets表示出现次数,viss表示出现没有. #include<iostream> #include<cstdio&g ...

  9. js 对象深复制,创建对象和继承

    js 对象深复制,创建对象和继承.主要参考高级编程第三版,总结网上部分资料和自己的代码测试心得.每走一小步,就做一个小结. 1.对象/数组深复制 一般的=号传递的都是对象/数组的引用,如在控制台输入 ...

  10. Javascript的delete

    Javascript中的激活对象(Activation object)和变量对象(Variable object):每个执行上下文在其内部都有一个Variable Object.与执行上下文类似,Va ...