博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript中的时间版运动
阅读量:6706 次
发布时间:2019-06-25

本文共 18900 字,大约阅读时间需要 63 分钟。

前面的话

  是指以速度为参照,随着路程的变化,时间随之变化;而时间版JS运动是指以时间为参照,随着路程的变化,速度随着变化。相较而言,时间版JS运动更为常用。JQ的就是时间版运动。本文将详细介绍时间版JS运动

 

速度版运动

  为何速度版JS更容易理解呢?这要归功于setInterval了。最容易想到的运行形式如下所示

setInterval(function(){    s = s + step},30)

  每30ms,路程增加step,实际上就决定了以速度为参照。而step的值如何变化就决定了何种运动形式。以最简单的匀速运动为例

  总路程s为150,每30ms,向前移动10,相当于速度为1000/3=333.3。最终计算得出花费时间t=s/v=150/333.3=0.45s

  当路程发生变化时,仍然以333.3的速度运动,时间也发生相应的变化。这就是速度版运动

 

公式推导

  下面来介绍时间版运动,以匀速运动为例,先假设几个变量

距离 c(change position)初始位置 b(beginning position)最终位置 p(position)持续时间 d(duration)时间 t(time)速度 v(velocity)

  上面几个变量有如下等式

  1、最终运动距离 = 最终位置 - 初始位置

c = p - b

  2、最终运动距离 = 速度 * 持续时间

c = v * d

  3、当前运动距离 = 当前位置 - 初始位置

c(当前) =  p(当前) - b

  4、当前运动距离 = 速度 * 时间

c(当前) = v * t

  最终要表示为如下函数

p(当前) = ƒ(t)

  因此,经过整理得出公式如下

p(当前) = b + c(当前) = b + v*t = b + c*t/d

  最终结果为

p = t * c / d + b

 

匀速函数

  下面将时间版匀速运动封装为一个名称为的文件

if (!window.requestAnimationFrame) {    requestAnimationFrame = function(fn) {        setTimeout(fn, 17);    };    }if (!window.cancelAnimationFrame) {    window.cancelAnimationFrame = function(id) {        clearTimeout(id);    };}function getCSS(obj,style){    if(window.getComputedStyle){        return getComputedStyle(obj)[style];    }    return obj.currentStyle[style];} function linearMove(obj,json,times,fn){  //获取当前毫秒数  var startTime = +new Date();    /*获取初始值*/  var iCur = {};  for(var attr in json){    if(attr == 'opacity'){      //对当前值的取值进行四舍五入,去除由于javascript小数计数中的bug存在的小尾巴      iCur[attr] = Math.round(getCSS(obj,attr)*100);    }else{      //去掉单位      iCur[attr] = parseInt(getCSS(obj,attr));    }  }  //清除定时器  cancelAnimationFrame(obj.timer);  obj.timer = requestAnimationFrame(function func(){    //获取t、d参数    var d = times;    var t = d - Math.max(0,startTime - (+new Date()) + d);    for(var attr in json){      /*获取b、c、p这三个参数*/      var b = iCur[attr];      var c = json[attr]-iCur[attr];      var p = t * ( c / d ) + b;      /*赋值操作*/      if(attr == 'opacity'){        obj.style.opacity = p / 100;        obj.style.filter = 'alpha(opacity=' + p + ')';      }else{        obj.style[attr] = p + 'px';      }      }      obj.timer = requestAnimationFrame(func);      /*运行指定时间后*/      if(t == d){        //清除定时器        cancelAnimationFrame(obj.timer);        //设置回调函数        fn && fn.call(obj);              }      });}

  下面调用自己封装的linearMove.js来制作一个实例

  
Document

 

Tween算法

  Tween是一个来自flash的运动算法,包含各种经典的动画运动公式,详细列表如下

Linear:线性匀速运动效果;Quadratic(Quad):二次方的缓动(t^2);Cubic:三次方的缓动(t^3);Quartic(Quart):四次方的缓动(t^4);Quintic(Quint):五次方的缓动(t^5);Sinusoidal(Sine):正弦曲线的缓动(sin(t));Exponential(Expo):指数曲线的缓动(2^t);Circular(Circ):圆形曲线的缓动(sqrt(1-t^2));Elastic:指数衰减的正弦曲线缓动;Back:超过范围的三次方缓动((s+1)*t^3 – s*t^2);Bounce:指数衰减的反弹缓动。

  每个效果都分三个缓动方式,分别是

easeIn:从0开始加速的缓动,也就是先慢后快;easeOut:减速到0的缓动,也就是先快后慢;easeInOut:前半段从0开始加速,后半段减速到0的缓动。

  所有的这些缓动算法都离不开下面4个参数,tbcd,含义如下:

t  当前时间 (time)b  初始位置 (beginning position)c  距离 (change position)d  持续时间 (duration)

  tween的详细算法如下

// Tween类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;        }    }};

  tween算法的精简版本如下所示

var Tween = {    linear: function (t, b, c, d){  //匀速        return c*t/d + b;    },    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;    },    easeBoth: function(t, b, c, d){  //加速减速曲线        if ((t/=d/2) < 1) {            return c/2*t*t + b;        }        return -c/2 * ((--t)*(t-2) - 1) + b;    },    easeInStrong: function(t, b, c, d){  //加加速曲线        return c*(t/=d)*t*t*t + b;    },    easeOutStrong: function(t, b, c, d){  //减减速曲线        return -c * ((t=t/d-1)*t*t*t - 1) + b;    },    easeBothStrong: 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;    },    elasticIn: function(t, b, c, d, a, p){  //正弦衰减曲线(弹动渐入)        if (t === 0) {             return b;         }        if ( (t /= d) == 1 ) {            return b+c;         }        if (!p) {            p=d*0.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;    },    elasticOut: function(t, b, c, d, a, p){    //正弦增强曲线(弹动渐出)        if (t === 0) {            return b;        }        if ( (t /= d) == 1 ) {            return b+c;        }        if (!p) {            p=d*0.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;    },        elasticBoth: function(t, b, c, d, a, p){        if (t === 0) {            return b;        }        if ( (t /= d/2) == 2 ) {            return b+c;        }        if (!p) {            p = d*(0.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 - 0.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 )*0.5 + c + b;    },    backIn: function(t, b, c, d, s){     //回退加速(回退渐入)        if (typeof s == 'undefined') {           s = 1.70158;        }        return c*(t/=d)*t*((s+1)*t - s) + b;    },    backOut: function(t, b, c, d, s){        if (typeof s == 'undefined') {            s = 3.70158;  //回缩的距离        }        return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;    },     backBoth: function(t, b, c, d, s){        if (typeof 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;    },    bounceIn: function(t, b, c, d){    //弹球减振(弹球渐出)        return c - Tween['bounceOut'](d-t, 0, c, d) + b;    },           bounceOut: 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 + 0.75) + b;        } else if (t < (2.5/2.75)) {            return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;        }        return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;    },          bounceBoth: function(t, b, c, d){        if (t < d/2) {            return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;        }        return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;    }}

 

JQ扩展

  默认地, JQ只有两种运动形式,包括linear和swing

jQuery.easing = {    linear: function( p ) {        return p;    },    swing: function( p ) {        return 0.5 - Math.cos( p * Math.PI ) / 2;    },    _default: "swing"};

  可以利用tween算法来扩展JQ的运动形式,JQ源码中关于运动形式的函数如下所示

this.pos = eased = jQuery.easing[ this.easing ](                percent, this.options.duration * percent, 0, 1, this.options.duration            );

  可以看到,它有5个参数,分别对应tween算法中的p、t、d、c、d,因此需要对tween算法中的参数进行修改

  下面利用扩展后的JQ插件来进行JQ的自定义运动

 

Tween函数

  下面基于上面的tween算法,对tween里面的所有运动形式进行封装,名称为

if (!window.requestAnimationFrame) {    requestAnimationFrame = function(fn) {        setTimeout(fn, 17);    };    }if (!window.cancelAnimationFrame) {    window.cancelAnimationFrame = function(id) {        clearTimeout(id);    };}function getCSS(obj,style){    if(window.getComputedStyle){        return getComputedStyle(obj)[style];    }    return obj.currentStyle[style];} // Tween类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;        }    }};  function tweenMove(obj,json,times,fx,fn){  //获取当前毫秒数  var startTime = +new Date();    /*获取初始值*/  var iCur = {};  for(var attr in json){    if(attr == 'opacity'){      //对当前值的取值进行四舍五入,去除由于javascript小数计数中的bug存在的小尾巴      iCur[attr] = Math.round(getCSS(obj,attr)*100);    }else{      //去掉单位      iCur[attr] = parseInt(getCSS(obj,attr));    }  }  //清除定时器  cancelAnimationFrame(obj.timer);  obj.timer = requestAnimationFrame(function func(){    //获取t、d参数    var d = times;    var t = d - Math.max(0,startTime - (+new Date()) + d);    for(var attr in json){      /*获取b、c、p这三个参数*/      var b = iCur[attr];      var c = json[attr]-iCur[attr];      var fxArr = fx.split('-');      if(fxArr.length == 2){        var p = Tween[fxArr[0]][fxArr[1]](t,b,c,d);      }else{        var p = Tween[fx](t,b,c,d);      }           /*赋值操作*/      if(attr == 'opacity'){        obj.style.opacity = p / 100;        obj.style.filter = 'alpha(opacity=' + p + ')';      }else{        obj.style[attr] = p + 'px';      }      }      obj.timer = requestAnimationFrame(func);      /*运行指定时间后*/      if(t == d){        //清除定时器        cancelAnimationFrame(obj.timer);        //设置回调函数        fn && fn.call(obj);              }      });}

  下面是一个实例演示

 

Tween演示

  下面利用封装好的运动框架对tween算法中所有的运动形式进行演示

 

转载于:https://www.cnblogs.com/xiaohuochai/p/7400210.html

你可能感兴趣的文章
像程序员一样地思考
查看>>
为什么你最后哪都没去!!
查看>>
X-FRAME-OPTIONS 防止点击劫持(Clickjacking)的方法
查看>>
软件开发平台有哪些种类联系和区别?
查看>>
单身女人要学会的
查看>>
eclipse中创建maven web项目
查看>>
我的友情链接
查看>>
Ubuntu10.4 桌面空白
查看>>
32位与64位操作系统区别
查看>>
kafka 的原理介绍
查看>>
我的友情链接
查看>>
How to Modify Public Network Information including VIP in Oracle Clusterware
查看>>
内网劫持渗透新姿势:MITMf简要指南
查看>>
动态规划-最长上升子序列(LIS)
查看>>
linux下mysql的root密码忘记解决方法
查看>>
我的友情链接
查看>>
运维经验分享(二)-- Linux Shell之ChatterServer服务控制脚本二次优化
查看>>
linux——源码编译安装httpd ERIKXUE薛忠权
查看>>
公司内部wiki 你建立了么
查看>>
Tiles简介
查看>>