JavaScript 渐变效果

简介:

程序集合了宽度、高度、透明度、top、left的渐变,可以自定义渐变项目和各个项目的初始值结束值,还能以任意点(定点)为中心渐变。

使用该程序能实现很多常见的动画特效,包括大小变换、位置变换、渐显渐隐等等。

 

效果:

5f98a0544d063f950e0c9afc37edac455e776dde

程序说明: 

渐变效果的原理就是利用定时器不断设置值,如果要减速效果就设置一个步长(详细看JavaScript 弹簧效果) 。
这里只是把能渐变的属性(透明度、宽、高、left、top)整合在一起,使用相同的渐变级数(Step)使渐变同步,形成多个属性同时渐变的效果。

下面说说有用的地方:

【最终样式】
JavaScript 图片切割效果的边宽获取中也说到了最终样式,在使用offset获取的数据设置宽度高度的时候,必须先减去最终样式中的边框宽度。
在这里我使用了muxrwc的在FF下实现currentStyle方法,这样在ff和ie都可以从currentStyle获取最终样式了:

ExpandedBlockStart.gif
if(!isIE){
    HTMLElement.prototype.__defineGetter__(
"currentStyle"function () {
        
return this.ownerDocument.defaultView.getComputedStyle(thisnull);
    });
}

使用这个获取边框宽度:

this ._xBorder  =   function (){  return  (parseInt(obj.currentStyle.borderLeftWidth)  +  parseInt(obj.currentStyle.borderRightWidth)); }
this ._yBorder  =   function (){  return  (parseInt(obj.currentStyle.borderTopWidth)  +  parseInt(obj.currentStyle.borderBottomWidth)); }

【宽度或高度优先】
宽度或高度优先其实就是先执行其中一个渐变,在完成后再执行另一个渐变。
渐变程序中在执行完一次渐变之后会返回一个bool值表示是否渐变完成,利用这个可以这样:

this .SetWidth()  &&   this .SetHeight();

由于&&的特性,当this.SetWidth()返回true时才会去执行this.SetHeight(),这也是不错的技巧。
同时为了同步渐变,另外的渐变使用了两倍的步长:

this.Step = 2*this.Step;
this.SetOpacity(); this.SetTop(); this.SetLeft();
this.Step = this.Step/2;

这样就能做出宽度或高度优先的效果了。
【定点渐变】
先说说原理,例如以宽度中点为参照点,可以想象如果宽度减少n,那只要left相对增加n*0.5(即n/2),
那么就可以做出以中点为中心变换的效果(当然要先把变换对象设为相对或绝对定位)。
那这个“0.5”怎么来的呢?有点数理知识应该知道就是渐变对象左边到变换点跟渐变对象总宽度的比
程序里用Width.pos保存这个值,在变换前先计算好变换点的位置:

this ._x  =   this ._obj.offsetLeft  +   this ._obj.offsetWidth  *   this .Width.pos;

每次变换都根据这个位置和宽度来重新设置left:

this ._obj.style.left  =   this ._x  -   this ._obj.offsetWidth  *   this .Width.pos  +   " px " ;

可能有人会说直接在原有left基础上加上变换宽度*Width.pos不是一样吗?
但问题是经过多次的变换计算(到达目标值前会有多次计算)之后得到的值已经不准确了。
因为在变换计算过程中很多小数会被忽略,随着计算次数增多结果的出入也越大,
所以先定好变换位置参照值(_x),这样不论经过多少次计算变换位置都不会走位了。

同理只要设置不同的Width.pos(包括负数和大于1的数)和Height.pos就可以以任意点为中心渐变了。

还有就是程序的设计也花了不少心思,为了提高整合度,做了一个FadeStruct的结构,其中run、start、end、target属性分别是是否渐变、开始值、结束值、目标值。
用了两次的Object.extend来设置默认值,详细可以看程序。

使用说明:

必要的参数只有一个,就是渐变对象,不过只有渐变对象是没有效果的,必须设置其他属性:
Opacity:透明渐变参数
Height:高度渐变参数
Width:宽度渐变参数
Top:Top渐变参数
Left:Left渐变参数
Step:10,//变化率
Time:10,//变化间隔
Mode:"both",//渐变顺序
Show:false,//是否默认打开状态
onFinish:function(){}//完成时执行

其中Opacity、Height、Width、Top、Left比较特别,是FadeStruct结构

例子里实例化这个对象:

var f = new Fade("idFade", { Show: true,
    Opacity: { run: 
true },
    Height: { run: 
true },
    Width: { run: 
true, pos: .5 },
    Top: { run: 
true, end: 70 }
});

设置run为true就表示开启这个变换,start和end是开始和结束值,pos是Height和Width特有的变换位置属性。

更详细的应用可以看实例。 
程序代码:

var isIE = (document.all) ? true : false;

var $ = function (id) {
    
return "string" == typeof id ? document.getElementById(id) : id;
};

if(!isIE){
    HTMLElement.prototype.__defineGetter__(
"currentStyle"function () {
        
return this.ownerDocument.defaultView.getComputedStyle(thisnull);
    });
}

var Class = {
  create: 
function() {
    
return function() {
      
this.initialize.apply(this, arguments);
    }
  }
}

Object.extend 
= function(destination, source) {
    
for (var property in source) {
        destination[property] 
= source[property];
    }
    
return destination;
}


var FadeStruct = function(options){
    
this.run = false;//是否渐变
    this.start = 0;//开始值
    this.end = 0;//结束值
    this.target = 0;//目标值
    Object.extend(this, options || {});
}

var Fade = Class.create();
Fade.prototype 
= {
  initialize: 
function(obj, options) {
    
    
var obj = $(obj);
    obj.style.overflow 
= "hidden";
    
this._obj = obj;
    
    
this._timer = null;//定时器
    this._finish = true;//是否执行完成
    this._fun = function(){};//渐变程序
    this._x = this._y = 0;//变换点位置
    
    
//设置获取透明度程序
    this._setOpacity = isIE ? function(opacity){ obj.style.filter = "alpha(opacity:" + opacity + ")"; } : function(opacity){ obj.style.opacity = opacity / 100; };
    
this._getOpacity = isIE ? function(){ return parseInt(obj.filters["alpha"].opacity); } : function(opacity){ return 100 * parseFloat(obj.currentStyle.opacity); };
    
    
//获取边框宽度程序
    this._xBorder = function(){ return (parseInt(obj.currentStyle.borderLeftWidth) + parseInt(obj.currentStyle.borderRightWidth)); }
    
this._yBorder = function(){ return (parseInt(obj.currentStyle.borderTopWidth) + parseInt(obj.currentStyle.borderBottomWidth)); }
    
    
this.SetOptions(options);
    
    
this.Mode = this.options.Mode;
    
this.Time = Math.abs(this.options.Time);
    
this.onFinish = this.options.onFinish;
    
    
//先设置特殊默认值
    this.Opacity = new FadeStruct({ end: 100 });
    
this.Top = new FadeStruct({ start: this._obj.offsetTop, end: this._obj.offsetTop });
    
this.Left = new FadeStruct({ start: this._obj.offsetLeft, end: this._obj.offsetLeft });
    
this.Height = new FadeStruct({ end: this._obj.offsetHeight - this._yBorder() });
    
this.Width = new FadeStruct({ end: this._obj.offsetWidth - this._xBorder() });
    
    
//再设置用户默认值
    Object.extend(this.Opacity, this.options.Opacity);
    Object.extend(
this.Top, this.options.Top);
    Object.extend(
this.Left, this.options.Left);
    Object.extend(
this.Height, this.options.Height);
    Object.extend(
this.Width, this.options.Width);
    
    
//变换位置参数
    this.Height.pos = Number(this.options.Height.pos);
    
this.Width.pos = Number(this.options.Width.pos);
    
    
//设置成默认状态
    this.Show = !this.options.Show;
    
this.Step = 1;
    
this.Start();
    
//重新设置Step
    this.Step = Math.abs(this.options.Step);
  },
  
//设置默认属性
  SetOptions: function(options) {
    
this.options = {//默认值
        Opacity:    {},//透明渐变参数
        Height:        {},//高度渐变参数
        Width:        {},//宽度渐变参数
        Top:        {},//Top渐变参数
        Left:        {},//Left渐变参数
        Step:        10,//变化率
        Time:        10,//变化间隔
        Mode:        "both",//渐变顺序
        Show:        false,//是否默认打开状态
        onFinish:    function(){}//完成时执行
    };
    Object.extend(
this.options, options || {});
  },        
  
//触发
  Start: function() {
    clearTimeout(
this._timer);
    
//取反表示要设置的状态
    this.Show = !this.Show;
    
//为避免透明度为null值,需要先设置一次透明度
    if(this.Opacity.run){ this._setOpacity(this.Show ? this.Opacity.start : this.Opacity.end); }
    
//根据状态设置目标值
    if(this.Show){
        
this.Opacity.target = this.Opacity.end;
        
this.Top.target = this.Top.end;
        
this.Left.target = this.Left.end;
        
this.Height.target = this.Height.end;
        
this.Width.target = this.Width.end;
    } 
else{
        
this.Opacity.target = this.Opacity.start;
        
this.Top.target = this.Top.start;
        
this.Left.target = this.Left.start;
        
this.Height.target = this.Height.start;
        
this.Width.target = this.Width.start;
    }
    
//设置渐变程序
    switch (this.Mode.toLowerCase()) {
        
case "width" :
            
this._fun = function(){
                
this.SetWidth() && this.SetHeight();
                
//由于分了两步,下面的步长变成两倍
                this.Step = 2*this.Step;
                
this.SetOpacity(); this.SetTop(); this.SetLeft();
                
this.Step = this.Step/2;
            }
            
break;
        
case "height" :
            
this._fun = function(){
                
this.SetHeight() && this.SetWidth();
                
//由于分了两步,下面的步长变成两倍
                this.Step = 2*this.Step;
                
this.SetOpacity(); this.SetTop(); this.SetLeft();
                
this.Step = this.Step/2;
            }
            
break;
        
case "both" :
        
default :
            
this._fun = function(){ this.SetHeight(); this.SetWidth(); this.SetOpacity(); this.SetTop(); this.SetLeft();}
    }
    
//获取变换点位置
    //由于设置变换点后与top和left变换有冲突只能执行其一
    if(this.Height.pos){ this._y = this._obj.offsetTop + this._obj.offsetHeight * this.Height.pos; this.Top.run = false; }
    
if(this.Width.pos){ this._x = this._obj.offsetLeft + this._obj.offsetWidth * this.Width.pos; this.Left.run = false; }
    
    
this.Run();
  },
  
//执行
  Run: function() {
    clearTimeout(
this._timer);
    
this._finish = true;
    
//执行渐变
    this._fun();
    
//未完成继续执行
    if (this._finish) { this.onFinish(); }
    
else { var oThis = thisthis._timer = setTimeout(function(){ oThis.Run(); }, this.Time); }
  },
  
//设置高度渐变
  SetHeight: function() {
    
var iGet = this.Get(this.Height, this._obj.offsetHeight - this._yBorder());
    
if(isNaN(iGet)) return true;
    

    
this._obj.style.height = iGet + "px";
    
//如果有变换点设置
    if(this.Height.pos){ this._obj.style.top = this._y - this._obj.offsetHeight * this.Height.pos + "px"; }
    
return false;
  },
  
//设置宽度渐变
  SetWidth: function() {
    
var iGet = this.Get(this.Width, this._obj.offsetWidth - this._xBorder());
    
if(isNaN(iGet)) return true;
    
    
this._obj.style.width = iGet + "px";
    
if(this.Width.pos){ this._obj.style.left = this._x - this._obj.offsetWidth * this.Width.pos + "px"; }
    
return false;
  },
  
//设置top渐变
  SetTop: function() {
    
var iGet = this.Get(this.Top, this._obj.offsetTop);
    
if(isNaN(iGet)) return true;
    
    
this._obj.style.top = iGet + "px";
    
return false;
  },
  
//设置left渐变
  SetLeft: function() {
    
var iGet = this.Get(this.Left, this._obj.offsetLeft);
    
if(isNaN(iGet)) return true;
    
    
this._obj.style.left = iGet + "px";
    
return false;
  },
  
//设置透明渐变
  SetOpacity: function() {
    
var iGet = this.Get(this.Opacity, this._getOpacity());
    
if(isNaN(iGet)) return true;
    
    
this._setOpacity(iGet);
    
return false;
  },
  
//获取设置值
  Get: function(o, now){
    
if(o.run){
        
var iStep = (o.target - now) / this.Step;
        
if(iStep){        
            
this._finish = false;
            
if(Math.abs(iStep) < 1){ iStep = iStep > 0 ? 1 : -1; }
            
return now + iStep;
        }
    }
  }
};

下载完整测试代码

本文转自博客园cloudgamer的博客,原文链接:JavaScript 渐变效果,如需转载请自行联系原博主。

相关文章
|
2月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
27 0
|
2月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
77 0
|
4天前
|
JavaScript 前端开发 测试技术
学习JavaScript
【4月更文挑战第23天】学习JavaScript
11 1
|
11天前
|
JavaScript 前端开发 应用服务中间件
node.js之第一天学习
node.js之第一天学习
|
1月前
|
运维 JavaScript 前端开发
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
|
1月前
|
JavaScript
Vue.js学习详细课程系列--共32节(4 / 6)
Vue.js学习详细课程系列--共32节(4 / 6)
35 0
|
1月前
|
前端开发 搜索推荐 JavaScript
编程笔记 html5&css&js 001 学习编程从网页开始
编程笔记 html5&css&js 001 学习编程从网页开始
|
2月前
|
前端开发 JavaScript
从零开始学习前端开发:HTML、CSS、JavaScript入门指南
【2月更文挑战第1天】本文将带领读者从零开始学习前端开发,介绍HTML、CSS和JavaScript的基础知识与应用,帮助读者快速入门前端开发领域。
65 1
|
2月前
|
数据采集 机器学习/深度学习 JavaScript
画【Python折线图】的一百个学习报告(二、pyecharts引入js文件)
画【Python折线图】的一百个学习报告(二、pyecharts引入js文件)
51 0
|
2月前
|
JSON 前端开发 JavaScript
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)
35 0
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)