Ruby's Louvre

The Crankiness of Belief achieves Great , not the Trick of Regulation.

javascript的缓动效果(第2部分)

这部分对原先的缓动函数进行抽象化,并结合缓动公式进行强化。成品的效果非常惊人逆天。走过路过不要错过。

好了,打诨到此为止。普通的加速减速是难以让人满意的,为了实现弹簧等让人眼花缭乱的效果必须动用缓动公式。我见过两套缓动公式,一套是早期Robert Penner大神的缓动公式,内置到tween类中,不过现在人们越来越推荐tweenlite这个新秀了。另一套是script.aculo.us与mootools里面的,由于mootools可称之为prototype的升级版,script.aculo.us则是基于prototype,我们就把它们并称为prototype流派。与flash流派最大的不同是,它们封装得更好,并只需传入一个参数(0~1的小数),并且拥有严密的队列机制来调用各种回调函数。如在回调函数设置元素的长宽,就弄成Scale特效,利用它我们进一步制作SlideUp,SlideDown,Squish等复合特效。

我们先来看flash流派的缓动公式,它们基本都有如下四个参数。

  • t:timestamp,指缓动效果开始执行到当前帧开始执行时经过的时间段,单位ms
  • b:beginning position,起始位置
  • c:change,要移动的距离,就是终点位置减去起始位置。
  • d: duration ,缓和效果持续的时间。

我们把这四个参数传入Robert Penner大神的缓动公式,它就会计算出当前帧物体移动的位置。我们对比原来的函数来改写。

  var transition = function(el){
    transition.linear = function(t,b,c,d){ return c*t/d + b; };//免费提供一个缓动公式(匀速运动公式)
    el.style.position = "absolute";
    var options = arguments[1] || {},
    begin =  getCoords(el).left,//开始位置
    change = parseFloat(getStyle(_("taxiway"),"width")) - parseFloat(getStyle(el,"width")),//要移动的距离
    duration = options.duration || 500,//缓动效果持续时间
    ease = options.ease || transition.linear,//要使用的缓动公式
    end = begin + change,//结束位置
    startTime = new Date().getTime();//开始执行的时间
    (function(){
      setTimeout(function(){
        var newTime = new Date().getTime(),//当前帧开始的时间
        timestamp = newTime - startTime;//逝去时间
        el.style.left = ease(timestamp,begin,change,duration) + "px";//移动
        if(duration <= timestamp){
          el.style.left = end + "px";
        }else{
          setTimeout(arguments.callee,25);//每移动一次停留25毫秒
        }
      },25)
    })()
  }

接着是各种缓动公式大阅兵,共分为十一大类,除了linear。其他类又分为三种。

  • easeIn方法控制补间如何从开始到最高速度。
  • easeOut 方法控制补间减速并停在目标位置
  • easeInOut方法同时控制上述两者。

具体公式见下面(共31种)。

//***********@author:Robert Penner and cloudgamer*************
//http://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html
  var Tween = {
    Linear: function(t,b,c,d){ return c*t/d + b; },
    Quad: {
      easeIn: function(t,b,c,d){
        return c*(t/=d)*t + b;
      },
      easeOut: function(t,b,c,d){
        return -c *(t/=d)*(t-2) + b;
      },
      easeInOut: function(t,b,c,d){
        if ((t/=d/2) < 1) return c/2*t*t + b;
        return -c/2 * ((--t)*(t-2) - 1) + b;
      }
    },
    Cubic: {
      easeIn: function(t,b,c,d){
        return c*(t/=d)*t*t + b;
      },
      easeOut: function(t,b,c,d){
        return c*((t=t/d-1)*t*t + 1) + b;
      },
      easeInOut: function(t,b,c,d){
        if ((t/=d/2) < 1) return c/2*t*t*t + b;
        return c/2*((t-=2)*t*t + 2) + b;
      }
    },
    Quart: {
      easeIn: function(t,b,c,d){
        return c*(t/=d)*t*t*t + b;
      },
      easeOut: function(t,b,c,d){
        return -c * ((t=t/d-1)*t*t*t - 1) + b;
      },
      easeInOut: function(t,b,c,d){
        if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
        return -c/2 * ((t-=2)*t*t*t - 2) + b;
      }
    },
    Quint: {
      easeIn: function(t,b,c,d){
        return c*(t/=d)*t*t*t*t + b;
      },
      easeOut: function(t,b,c,d){
        return c*((t=t/d-1)*t*t*t*t + 1) + b;
      },
      easeInOut: function(t,b,c,d){
        if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
        return c/2*((t-=2)*t*t*t*t + 2) + b;
      }
    },
    Sine: {
      easeIn: function(t,b,c,d){
        return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
      },
      easeOut: function(t,b,c,d){
        return c * Math.sin(t/d * (Math.PI/2)) + b;
      },
      easeInOut: function(t,b,c,d){
        return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
      }
    },
    Expo: {
      easeIn: function(t,b,c,d){
        return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
      },
      easeOut: function(t,b,c,d){
        return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
      },
      easeInOut: function(t,b,c,d){
        if (t==0) return b;
        if (t==d) return b+c;
        if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
        return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
      }
    },
    Circ: {
      easeIn: function(t,b,c,d){
        return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
      },
      easeOut: function(t,b,c,d){
        return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
      },
      easeInOut: function(t,b,c,d){
        if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
        return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
      }
    },
    Elastic: {
      easeIn: function(t,b,c,d,a,p){
        if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
        if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
        else var s = p/(2*Math.PI) * Math.asin (c/a);
        return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
      },
      easeOut: function(t,b,c,d,a,p){
        if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
        if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
        else var s = p/(2*Math.PI) * Math.asin (c/a);
        return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
      },
      easeInOut: function(t,b,c,d,a,p){
        if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
        if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
        else var s = p/(2*Math.PI) * Math.asin (c/a);
        if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
        return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
      }
    },
    Back: {
      easeIn: function(t,b,c,d,s){
        if (s == undefined) s = 1.70158;
        return c*(t/=d)*t*((s+1)*t - s) + b;
      },
      easeOut: function(t,b,c,d,s){
        if (s == undefined) s = 1.70158;
        return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
      },
      easeInOut: function(t,b,c,d,s){
        if (s == undefined) s = 1.70158; 
        if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
        return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
      }
    },
    Bounce: {
      easeIn: function(t,b,c,d){
        return c - Tween.Bounce.easeOut(d-t, 0, c, d) + b;
      },
      easeOut: function(t,b,c,d){
        if ((t/=d) < (1/2.75)) {
          return c*(7.5625*t*t) + b;
        } else if (t < (2/2.75)) {
          return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
        } else if (t < (2.5/2.75)) {
          return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
        } else {
          return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
        }
      },
      easeInOut: function(t,b,c,d){
        if (t < d/2) return Tween.Bounce.easeIn(t*2, 0, c, d) * .5 + b;
        else return Tween.Bounce.easeOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
      }
    }
  }
<div id="taxiway">
  <div id="move" onclick="transition(this,{ease:Tween.Bounce.easeOut})"></div>
</div>

但我不喜欢flash流派的缓动公式,为了使用prototype流派的缓动公式,我进一步改进与抽象化我的缓动函数

//******************@author : 司徒正美************
  var transition = function(el){
    el.style.position = "absolute";
    var options = arguments[1] || {},
    begin =  options.begin,//开始位置
    change = options.change,//变化量
    duration = options.duration || 500,//缓动效果持续时间
    field = options.field,//必须指定,基本上对top,left,width,height这个属性进行设置
    ftp = options.ftp || 50,
    onStart = options.onStart || function(){},
    onEnd = options.onEnd || function(){},
    ease = options.ease,//要使用的缓动公式
    end = begin + change,//结束位置
    startTime = new Date().getTime();//开始执行的时间
    onStart();
    (function(){
      setTimeout(function(){
        var newTime = new Date().getTime(),//当前帧开始的时间
        timestamp = newTime - startTime,//逝去时间
        delta = ease(timestamp / duration);
        el.style[field] = Math.ceil(begin + delta * change) + "px"
        if(duration <= timestamp){
          el.style[field] = end + "px";
          onEnd();
        }else{
          setTimeout(arguments.callee,1000/ftp);
        }
      },1000/ftp)
    })()
  }
参数 类型 说明
el element 必需,为页面元素
begin number 必需,开始的位置
change number 必需,要移动的距离
duration number 可选,缓动效果持续时间,默认是500ms。建议取300~1000ms。
field string 必需,要发生变化的样式属性。请在top,left,bottom,right,width与height中选择。
ftp number 可选,每秒进行多少帧动画,默认50帧,保证流畅播放。一些参考资料,日本动画1秒36帧,中国卡通24帧,赛车游戏60帧。
ease function 必需,缓动公式,参数为0~1之间的数。可参考我下面给出的45条公式。
onStart function 可选,在开始时执行。
onEnd function 可选,在结束时执行。

prototype流派的缓动公式,只需一个参数(增至45种)

var tween = {
    easeInQuad: function(pos){
      return Math.pow(pos, 2);
    },

    easeOutQuad: function(pos){
      return -(Math.pow((pos-1), 2) -1);
    },

    easeInOutQuad: function(pos){
      if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,2);
      return -0.5 * ((pos-=2)*pos - 2);
    },

    easeInCubic: function(pos){
      return Math.pow(pos, 3);
    },

    easeOutCubic: function(pos){
      return (Math.pow((pos-1), 3) +1);
    },

    easeInOutCubic: function(pos){
      if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,3);
      return 0.5 * (Math.pow((pos-2),3) + 2);
    },

    easeInQuart: function(pos){
      return Math.pow(pos, 4);
    },

    easeOutQuart: function(pos){
      return -(Math.pow((pos-1), 4) -1)
    },

    easeInOutQuart: function(pos){
      if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,4);
      return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);
    },

    easeInQuint: function(pos){
      return Math.pow(pos, 5);
    },

    easeOutQuint: function(pos){
      return (Math.pow((pos-1), 5) +1);
    },

    easeInOutQuint: function(pos){
      if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,5);
      return 0.5 * (Math.pow((pos-2),5) + 2);
    },

    easeInSine: function(pos){
      return -Math.cos(pos * (Math.PI/2)) + 1;
    },

    easeOutSine: function(pos){
      return Math.sin(pos * (Math.PI/2));
    },

    easeInOutSine: function(pos){
      return (-.5 * (Math.cos(Math.PI*pos) -1));
    },

    easeInExpo: function(pos){
      return (pos==0) ? 0 : Math.pow(2, 10 * (pos - 1));
    },

    easeOutExpo: function(pos){
      return (pos==1) ? 1 : -Math.pow(2, -10 * pos) + 1;
    },

    easeInOutExpo: function(pos){
      if(pos==0) return 0;
      if(pos==1) return 1;
      if((pos/=0.5) < 1) return 0.5 * Math.pow(2,10 * (pos-1));
      return 0.5 * (-Math.pow(2, -10 * --pos) + 2);
    },

    easeInCirc: function(pos){
      return -(Math.sqrt(1 - (pos*pos)) - 1);
    },

    easeOutCirc: function(pos){
      return Math.sqrt(1 - Math.pow((pos-1), 2))
    },

    easeInOutCirc: function(pos){
      if((pos/=0.5) < 1) return -0.5 * (Math.sqrt(1 - pos*pos) - 1);
      return 0.5 * (Math.sqrt(1 - (pos-=2)*pos) + 1);
    },

    easeOutBounce: function(pos){
      if ((pos) < (1/2.75)) {
        return (7.5625*pos*pos);
      } else if (pos < (2/2.75)) {
        return (7.5625*(pos-=(1.5/2.75))*pos + .75);
      } else if (pos < (2.5/2.75)) {
        return (7.5625*(pos-=(2.25/2.75))*pos + .9375);
      } else {
        return (7.5625*(pos-=(2.625/2.75))*pos + .984375);
      }
    },

    easeInBack: function(pos){
      var s = 1.70158;
      return (pos)*pos*((s+1)*pos - s);
    },

    easeOutBack: function(pos){
      var s = 1.70158;
      return (pos=pos-1)*pos*((s+1)*pos + s) + 1;
    },

    easeInOutBack: function(pos){
      var s = 1.70158;
      if((pos/=0.5) < 1) return 0.5*(pos*pos*(((s*=(1.525))+1)*pos -s));
      return 0.5*((pos-=2)*pos*(((s*=(1.525))+1)*pos +s) +2);
    },

    elastic: function(pos) {
      return -1 * Math.pow(4,-8*pos) * Math.sin((pos*6-1)*(2*Math.PI)/2) + 1;
    },

    swingFromTo: function(pos) {
      var s = 1.70158;
      return ((pos/=0.5) < 1) ? 0.5*(pos*pos*(((s*=(1.525))+1)*pos - s)) :
        0.5*((pos-=2)*pos*(((s*=(1.525))+1)*pos + s) + 2);
    },

    swingFrom: function(pos) {
      var s = 1.70158;
      return pos*pos*((s+1)*pos - s);
    },

    swingTo: function(pos) {
      var s = 1.70158;
      return (pos-=1)*pos*((s+1)*pos + s) + 1;
    },

    bounce: function(pos) {
      if (pos < (1/2.75)) {
        return (7.5625*pos*pos);
      } else if (pos < (2/2.75)) {
        return (7.5625*(pos-=(1.5/2.75))*pos + .75);
      } else if (pos < (2.5/2.75)) {
        return (7.5625*(pos-=(2.25/2.75))*pos + .9375);
      } else {
        return (7.5625*(pos-=(2.625/2.75))*pos + .984375);
      }
    },

    bouncePast: function(pos) {
      if (pos < (1/2.75)) {
        return (7.5625*pos*pos);
      } else if (pos < (2/2.75)) {
        return 2 - (7.5625*(pos-=(1.5/2.75))*pos + .75);
      } else if (pos < (2.5/2.75)) {
        return 2 - (7.5625*(pos-=(2.25/2.75))*pos + .9375);
      } else {
        return 2 - (7.5625*(pos-=(2.625/2.75))*pos + .984375);
      }
    },

    easeFromTo: function(pos) {
      if ((pos/=0.5) < 1) return 0.5*Math.pow(pos,4);
      return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);
    },

    easeFrom: function(pos) {
      return Math.pow(pos,4);
    },

    easeTo: function(pos) {
      return Math.pow(pos,0.25);
    },

    linear:  function(pos) {
      return pos
    },

    sinusoidal: function(pos) {
      return (-Math.cos(pos*Math.PI)/2) + 0.5;
    },

    reverse: function(pos) {
      return 1 - pos;
    },

    mirror: function(pos, transition) {
      transition = transition || tween.sinusoidal;
      if(pos<0.5)
        return transition(pos*2);
      else
        return transition(1-(pos-0.5)*2);
    },

    flicker: function(pos) {
      var pos = pos + (Math.random()-0.5)/5;
      return tween.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);
    },

    wobble: function(pos) {
      return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
    },

    pulse: function(pos, pulses) {
      return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
    },

    blink: function(pos, blinks) {
      return Math.round(pos*(blinks||5)) % 2;
    },

    spring: function(pos) {
      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
    },

    none: function(pos){
      return 0
    },

    full: function(pos){
      return 1
    }
  }

除了这45条公式外,我们还可以制定自己的缓动公式。正如我在上面表格中提到, 它在运行过程是不执行回调函数时,但你们可以在运行框中看到,我可以实现一边移动一边记录点的坐标。这是怎样实现的呢? 我们只要把上面的缓动公式的任何一条塞进一个只有一个参数的函数就行了。当然此函数要有返回,供继续向下调用。以下就是一个模板:

  var myTween = function(pos){ //缓动公式
      var value = tween[ease](pos);
      //***********这上面是固定的**************
      indicator.style.display = "block";
      marker.style.display = "block";
      marker.style.left = Math.round((pos*200))+'px';
      marker.style.bottom = Math.round(((value*200)-min)*factor)+'px';
      label.innerHTML = Math.round((pos*200))+'px';
      //************这下面是固定的*************
      return value;
    }

更多示例,不懂再留言给我。

 <div class="taxiway">
  <div class="move" onclick="transition(this,{field:'left',begin:parseFloat(getCoords(this).left),change:700,ease:tween.bouncePast})"></div>
</div>
<div class="taxiway">
  <div class="move" onclick="transition(this,{field:'width',begin:parseFloat(getStyle(this,'width')),change:300,ease:tween.spring})"></div>
</div>
标签: javascript

posted on 2009-09-17 04:18 司徒正美 阅读(4496) 评论(31) 编辑 收藏

评论

#1楼 2009-09-17 06:50 Astar      

支持楼主,不得不说在这里学到了很多!  回复 引用 查看   

#2楼 2009-09-17 07:18 锦瑟[未注册用户]

这样的效果在wpf,silverlight里可以轻松实现,用javascript搞这些东西实在是太有耐心了……  回复 引用   

#3楼 2009-09-17 07:41 徐少侠      

狠啊

太有价值的东西了

至少里面那么多的公式就值得收藏了

谢谢
 回复 引用 查看   

#4楼 2009-09-17 08:10 OctoberOne      

 回复 引用 查看   

#5楼 2009-09-17 08:13 金色海洋(jyk)      

太厉害了,请教一个问题好吗?

我想在前台用js的方法来获取table里的td的内容。

我用 table.rows[0].cells[0].innerText的方式来获取,这个在IE6里面好用,但是在FireFox里面就不行了 ,请问在Firefox、IE7里面要怎么写呢?

谢谢了!
 回复 引用 查看   

#6楼 2009-09-17 08:14 字字谣      

太强了!  回复 引用 查看   

#7楼 2009-09-17 08:40 Hunts.C      

赞一个  回复 引用 查看   

#8楼 2009-09-17 08:42 Gnie      

牛了!  回复 引用 查看   

#9楼 2009-09-17 08:47 颜斌      

引用金色海洋(jyk):
太厉害了,请教一个问题好吗?

我想在前台用js的方法来获取table里的td的内容。

我用 table.rows[0].cells[0].innerText的方式来获取,这个在IE6里面好用,但是在FireFox里面就不行了 ,请问在Firefox、IE7里面要怎么写呢?

谢谢了!

.textContent  回复 引用 查看   

#10楼 2009-09-17 08:49 Jimixu      

@锦瑟
光说不练,假把式。wpf和sl都普及了么?过分依赖微软的东西不是好事。LZ的强大是显而易见的。
 回复 引用 查看   

#11楼 2009-09-17 09:11 Jonllen Peng      

ff内无innerText方式获取,innerHTML都通用吧.  回复 引用 查看   

#12楼 2009-09-17 09:12 KevinDiao      

IE6中有点兼容性问题!那线条不变粗了
 回复 引用 查看   

#13楼 2009-09-17 09:31 金色海洋(jyk)      

@颜斌
FireFox 里面支持.textContent,但是IE6里面不支持.textContent,真郁闷。

我没有安装IE7,不知道IE7、IE8支持哪一个?

另外好像FireFox里面也不支持 opener. 的这种方法。

其实FireFox可以先不管,但是主要是我不知道ie7是什么情况。
 回复 引用 查看   

#14楼 2009-09-17 09:34 金色海洋(jyk)      

引用Jonllen Peng:ff内无innerText方式获取,innerHTML都通用吧.

谢谢提醒,刚才试了一下,innerHTML都可以用。

只顾着测试innerText了,忘了innerHTML。(因为我是想提取纯文字的,呵呵)  回复 引用 查看   

#15楼 2009-09-17 09:53 Google优化      

js存在一个跨浏览器问题!太复杂的东西并不是很好解决!除非使用js框架!google优化  回复 引用 查看   

#16楼 2009-09-17 10:08 Studyer[未注册用户]

楼主能不能给推荐几个好的网址和您说的几个大神的博客?  回复 引用   

#17楼 2009-09-17 10:26 xjy      

留个脚印。LZ有空可以发点关于火狐下面一些事件的帖子吗?Asp.Net的文本框在火狐下按回车 总是有问题。  回复 引用 查看   

#18楼[楼主] 2009-09-17 10:55 司徒正美      

@KevinDiao
这个我知道,因为这些曲线全是一个个1*1的绝对定位的div组成,font-size为零大法与overflow:hidden大法在这么快的渲染中好像跟不上了。这次真的完全败给IE6了。
幸好还算好看,将就吧。

@xjy
Asp.Net不是有自己的JS框架吗?没有研究过那个。
我在博客中有专门的文章研究键盘的事件绑定,你自己可以去看看
http://www.cnblogs.com/rubylouvre/archive/2009/08/20/1550526.html
 回复 引用 查看   

#19楼 2009-09-17 11:06 xjy      

@司徒正美
3Q
 回复 引用 查看   

#20楼 2009-09-17 11:09 卡通一下      

顶一个!

比那些只会胡侃技术的实用多了。
 回复 引用 查看   

#21楼 2009-09-17 13:44 →province★      

引用卡通一下:
顶一个!

比那些只会胡侃技术的实用多了。

 回复 引用 查看   

#22楼 2009-09-17 17:04 小 严      

是的,不要胡侃技术  回复 引用 查看   

#23楼 2009-09-17 17:27 不能飚车      

LZ很强大,这个很有用  回复 引用 查看   

#24楼 2009-09-17 22:51 一抹红      

很好很强大,对了,顺便问下lz,你写JS代码用的运行环境是什么啊,能不能想VS2008一样很好的调试编译啊  回复 引用 查看   

#25楼[楼主] 2009-09-18 00:01 司徒正美      

@一抹红
一直用netBeans,喜欢它强大的代码提示与排版功能,调试更不在话下。不过,我基本都是手写代码,然后用它的排版功能对齐一下就算了。没有用过VS2008,VS2003用了很短时间就删了,体积太大浪费空间!
 回复 引用 查看   

#26楼 2009-09-18 00:27 一抹红      

@司徒正美
呵呵,看来LZ是前台高手,望尘莫及啊
 回复 引用 查看   

#27楼 2009-09-18 07:54 回头重来      

学习了。  回复 引用 查看   

#28楼 2009-09-18 08:47 1-2-3      

很强大,收藏了。  回复 引用 查看   

#29楼 2009-09-19 10:46 甚好[未注册用户]

引用1-2-3:很强大,收藏了。

非常有用!

老赵只会夸夸其谈!
 回复 引用   

#30楼 2009-10-10 14:25 小眼睛老鼠      

@甚好
老赵也是非常牛逼的
不过方向不同而已
如果你到了老赵的层次,你就会知道他的实力了
老赵的有些理论在新手看来太过于高深了
 回复 引用 查看   

#31楼 2011-04-01 11:56 流浪啊      

@金色海洋(jyk)

ie innerText
ff textContent
 回复 引用 查看