zoukankan      html  css  js  c++  java
  • Dom元素变换效果(工具函数)

      文章前声明:下文的运行效果在ie下由于和博客的session有命名冲突,所以不能正常运行,ff ,chrome没问题,用ie的同学要看演示请自行把代码考到本地运行...

      做前端或者js程序员的同学应该都有感受,在日常工作中,用的最多的功能,一个是ajax与后台的数据接口,另一个就是对Dom元素的style控制,来达到不同的变换效果。用js来控制行为,控制页面表现。恐怕是我们用它来做的最多的事情了...
      jQuery为什么这么受欢迎,我想,一方面是它的选择器[selector]足够牛B,另一方面应该要归功于它在dom变换上做足了功夫。

      于是,秉承着一个宅男的宗旨,周末花了两个晚上稍微总结了一下,写了一段控制dom元素变换的代码,与目前强大的框架比起来,确实显得有点拙劣,不过作为日常开发的工具函数,我想还是蛮实用的。(这也是我最初的目的 ^_^)。

      开门见山,先把源码完整的贴出来:(本着分享学习的原则,源代码你可以任意修改)

    代码
    //////////////* = Hongru.anim.js =*///////////
    //
    @author: hongru.chen //
    //
    @date: 2010-10-17 //
    //
    //////////////////////////////////////////

    var Hongru = {
    get :
    function (id) {return document.getElementById(id)},
    tween : {
    linear :
    function (f, t, d) { return t * d + f; },
    ease :
    function (f, t, d) { return -t * .5 * (Math.cos(Math.PI * d) - 1) + f; }
    },
    tweens: [],
    tweensCnt:
    0,
    anim :
    function (obj, params) {
    var self = this,
    objList
    = [],
    objReturn
    = [];
    var animimg = function () {
    var i = -1, o;
    while( o = self.tweens[++i] ) {
    var cTime = (new Date()).getTime() - o.start;
    if (cTime < o.duration) {
    for (var k in o.val) {
    var m = o.val[k];
    o.obj[k]
    = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
    }
    }
    else {
    cTime
    = o.duration;
    for (var k in o.val) {
    var m = o.val[k];
    o.obj[k]
    = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
    }
    self.tweens.splice(i,
    1);
    self.tweensCnt
    --;
    if (o.onFinish) o.onFinish (o.params);
    self.stop();
    }
    if (!o.cssMode) o.obj.onTween();
    }
    };
    if (typeof obj == "string" || !obj.length) objList.push(obj); else objList = obj;
    for (var il = 0, l = objList.length; il < l; il++) {
    var obj = this.get(objList[il]) || objList[il];
    var o = {};
    o.val
    = {};
    o.cssMode
    = true;
    o.o
    = obj;
    o.obj
    = obj.style;
    for (var k in params) {
    var p = params[k];
    if (k === "cssMode") {
    if (p === false) {
    o.cssMode
    = false;
    o.obj
    = obj;
    }
    }
    else if (k === "onTween") {
    o.obj.onTween
    = p;
    }
    else if (k === "from") {
    for (var i in p) o.obj[i] = o.cssMode ? (Math.ceil(p[i]) + 'px') : p[i];
    }
    else if (k === "to") {
    for (var i in p) {
    var from = o.cssMode ? (parseInt(o.obj[i]) || 0) : (o.obj[i] || 0);
    o.val[i]
    = {
    from: from,
    diff: p[i]
    - from
    };
    }
    }
    else o[k] = params[k];
    }
    if (!o.ease) o.ease = this.tween.ease;
    if (!o.cssMode && params['from']) o.obj.onTween();
    o.duration
    = params.duration ? params.duration : 1000;
    o.start
    = (new Date()).getTime();
    this.tweens.push(o);
    this.tweensCnt++;
    if (!this.running) this.running = window.setInterval(animimg, 10);
    objReturn.push(o);
    }
    return objReturn.length === 1 ? o : objReturn;
    },
    stop :
    function () {
    if (!this.tweensCnt) {
    window.clearInterval(
    this.running);
    this.running = false;
    }
    },
    kill :
    function (obj) {
    if (obj) {
    for (var i = 0; i < this.tweensCnt; i++) {
    if (this.tweens[i] === obj || this.tweens[i].o === obj || this.tweens[i].o === this.get(obj)) {
    this.tweensCnt--;
    this.tweens.splice(i, 1);
    this.stop();
    }
    }
    }
    },
    reset :
    function () {
    this.tweensCnt = 0;
    this.stop();
    while( this.tweens.length ) {
    this.tweens.stop();
    }
    }
    }

      从调用方式来看,其实我的实现方法有点类似于YUI,以下是个最简单的例子:

    Hongru.anim(id, {
    from: {
    top:
    0,
    left:
    100
    },
    to: {
    left:
    500,
    }

    });

    以下是调用这段代码的效果:

    当然,这是最简单的方式,此外,我在参数id上,花了点小心思,anim()的第一个参数不仅可以是我们常见的字符串"id",也可以是HtmlObject,比如同样是上面的代码:

    function tween1 (id) { //此id参数可以是obj,也可以是字符串id,还可以是数组['id1','id2','id3']
    Hongru.anim(id, {
    from: {
    top:
    0,
    left:
    100
    },
    to: {
    left:
    500,
    }

    });
    }

    可以对一个元素这样来调用

    onclick="tween1(this)"

    this直接指向元素本身,演示如下。

    另外,还可以控制多个元素同时变换,也就是说,id可以是个数组如['id1', 'id2', 'id3'].演示如下:

      以上可以支持object和数组selector的功能,暂可以称为【功能一】

      【功能二】

    支持回调函数callback,也就是可以实现咱们常说的chain-animate,链式变换。具体是通过onFinish参数来实现的。核心源码很简单,就是在一个变换完毕之后判断有没有onFinish,如果有就调用:

    代码
    var animimg = function () {
    var i = -1, o;
    while( o = self.tweens[++i] ) {
    var cTime = (new Date()).getTime() - o.start;
    if (cTime < o.duration) {
    for (var k in o.val) {
    var m = o.val[k];
    o.obj[k]
    = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
    }
    }
    else {
    cTime
    = o.duration;
    for (var k in o.val) {
    var m = o.val[k];
    o.obj[k]
    = Math.ceil(o.ease(m.from, m.diff, cTime/o.duration)) + (o.cssMode ? 'px' : 0);
    }
    self.tweens.splice(i,
    1);
    self.tweensCnt
    --;
    if (o.onFinish) o.onFinish (o.params);
    self.stop();
    }
    if (!o.cssMode) o.obj.onTween();
    }
    };

    下面是通过递归调用实现chain-animate的一个演示:

    到这里,相信以前做过类似工作的同学们都觉得这还不够,毕竟如果只实现所有和‘盒模型’沾边的属性的变换应该都不算难事。比如高宽,padding,margin,left,top等等这些可以用像素做单位的属性。他们的变换都可以统一起来。但是如果要实现颜色变换,透明度变换呢,恐怕就不是我的短短几十百来行代码就可以做到的。

    是的,我承认,要把颜色,透明度等等所有属性变换都封装起来,需要做的判断就不是一点两点了。所以呢,在这里,我也没有对“盒模型”以外的属性变换做封装。但并不代表没有想到他们的实现方法。

      既然写死在代码里要费事,那就我们自己调用的时候多写两句代码不就好了吗,毕竟代码是死的,人是活的。我这里做了个cssMode的参数判断(思路是借鉴一个老外的)。代码成本很低。如果不是可以用px做单位的属性,我们可以自己控制它的样式变换。比如实现背景色变换:

    function test3 (id) {
    Hongru.anim(id, {
    cssMode:
    false, // animation will be handled by an external function
    onTween : function () {
    // custom function, can be as simple or as complex as needed
    this.style.background = "RGB("+this.r+","+this.g+","this.b")";
    },
    from : { r:
    0, g: 0, b: 0 },
    to: { r:
    255, g: 128, b: 100 }
    });
    }

    把cssMode设置为false之后,会执行onTween里的代码,这样就可以自行控制样式的变换了,如上。演示如下:

    同样,透明度也可以自行设置,

    好了,鉴于篇幅和时间,此文基本都在介绍功能,对代码没怎么细讲,有兴趣的同学可以自己看看,反正源码也贴出来了,而且原理都不难。

    另外,在这个函数使用中,Hongru.kill(id)是停止指定对象的变换。Hongru.reset()是停止所有正在变换的效果。至于Hongru本身,大家可以随意更改。

    时间不早了,洗洗睡吧

  • 相关阅读:
    ajax异步上传图片&SpringMVC后台代码
    Jdk与Tomcat配置与安装
    Jpa常用注解@Test
    关于ssh和ajax小小总结
    关于EL表达式的大小写问题。谁来帮我解答?
    关于spring管理hibernate事物
    关于session更新的问题
    ssh使用ajax异步通讯. json与对象转换的几个小问题
    通过http Post XML文件的接口 (System.Web.IHttpHandler)
    HTTP Post方法
  • 原文地址:https://www.cnblogs.com/hongru/p/1853917.html
Copyright © 2011-2022 走看看