JavaScript 实现可控式透明渐变特效的完整代码与优化

作者:像素漫游时间:2026-10-24 13:20:39浏览:359

本文详细介绍如何使用 JavaScript 实现可控的透明渐变特效。通过 setTimeout 递归模拟 setInterval,逐步构建基础淡入效果,并解决 IE 滤镜兼容性问题。文章进一步提供可配置参数的增强版本,修复数字参数转换 Bug,最终利用原型链优化代码结构,实现高效复用的透明动画组件。

基于 setTimeout 递归的透明特效基础实现

元素的空间位移完全依赖 CSS 的绝对定位来实现。在正式编写特效之前,我们先通过一个示例练习 setTimeout 的递归调用技巧,这可以用来模拟 setInterval 的行为。


具体实现代码如下:

 
function text(el){
var node = (typeof el == "string")? document.getElementById(el) : el;
var i = 0;
var repeat = function(){
setTimeout(function(){
node.innerHTML = "<h1>"+i+"</h1>";
i++;
if(i <= 100){
setTimeout(arguments.callee, 100);
} 
},100)
} 
repeat();
} 

接下来,我们尝试实现最简单的淡入特效。主要思路是将更新 innerHTML 的代码替换为对元素透明度的设置。


相关代码如下:

 
function fadeIn(el){
var node = (typeof el == "string")? document.getElementById(el) : el;
var i = 0;
var fade = function(){
setTimeout(function(){
!+"\v1"? (node.style.filter="alpha(opacity="+i+")"): (node.style.opacity = i / 100);
i++;
if(i <= 100){
setTimeout(arguments.callee, 100);
} 
},100)
} 
fade();
} 

增强版:支持参数配置与 IE 兼容性处理

然而,上述实现并不完美。在 IE7 等旧版浏览器中,滤镜可能会失效,因此必须通过设置 zoom=1 来激活 hasLayout 属性。此外,我们需要添加更多可定制参数以增强功能。代码注释已非常详细,如有疑问请在留言区提出。


优化后的代码如下:

 
function opacity(el){
//必选参数
var node = (typeof el == "string")? document.getElementById(el) : el,
//可选参数
options = arguments[1] || {},
//变化的持续时间
duration = options.duration || 1.0,
//开始时透明度
from = options.from || 0.0 ,
//结束时透明度
to = options.to || 0.5,
operation = 1,
init = 0;
if(to - from < 0){
operation = -1,
init = 1;
} 
//内部参数
//setTimeout执行的间隔时间,单位毫秒
var frequency = 100,
//设算重复调用的次数
count = duration * 1000 / frequency,
// 设算每次透明度的递增量
detal = Math.abs(to - from) /count,
// 正在进行的次数
i = 0;
var main = function(){
setTimeout(function(){
if(!+"\v1"){
if(node.currentStyle.hasLayout) node.style.zoom = 1;//防止滤镜失效
node.style.filter="alpha(opacity="+ (init * 100 + operation * detal * i * 100).toFixed(1) +")"
}else{
node.style.opacity = (init + operation * detal * i).toFixed(3)
} 
node.innerHTML = (init + operation * detal * i).toFixed(3)
i++;
if(i <= count){
setTimeout(arguments.callee, frequency);
} 
},frequency)
} 
main();
} 

效果演示如下:


<style> .text {width:100px;height:100px;background:red;display:inline-block;} </style> <div class="text" onclick="opacity(this,{duration:4.0,from:0.0,to:1})"></div> <div class="text" onclick="opacity(this,{duration:4.0,from:1.0,to:0})"></div>  

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]


<div class="text" onclick="opacity(this,{duration:4.0,from:0.0,to:1})"></div>


<div class="text" onclick="opacity(this,{duration:4.0,from:1.0,to:0})"></div>


Bug 修复:处理数字参数转换与循环逻辑优化

尽管上述代码已具备一定功能,但仍存在一个 Bug。我们使用短路运算符来决定使用默认参数还是传入参数,但在 JavaScript 中,数字 0 或 0.0 会被自动转换为 false。因此,在第二个示例中,如果传入的 to 值为 0,它永远不会被使用,而是回退到默认值 0.5。解决方法是将该参数转换为字符串 "0"。另外,参数 i 并非必需,我们可以省略它,仅使用 count 负责所有循环逻辑,但这需要逆向思维:原本递增的操作需改为递减。


修正后的代码如下:

 
function opacity(el){
//必选参数
var node = (typeof el == "string")? document.getElementById(el) : el,
//可选参数
options = arguments[1] || {},
//变化的持续时间
duration = options.duration || 1.0,
//开始时透明度
from = options.from || 0.0 ,
//结束时透明度
to = (options.to && options.to + "") || 0.5,
operation = -1,
init = 1;
if(to - from < 0){
operation = 1,
init = 0;
} 
//内部参数
//setTimeout执行的时间,单位
var frequency = 100,
//设算重复调用的次数
count = duration * 1000 / frequency,
// 设算每次透明度的递增量
detal = operation * Math.abs(to - from) /count;
var main = function(){
setTimeout(function(){
if(!+"\v1"){
if(node.currentStyle.hasLayout) node.style.zoom = 1;//防止滤镜失效
node.style.filter="alpha(opacity="+ (init * 100 + detal * count * 100).toFixed(1) +")"
}else{
node.style.opacity = (init + detal * count).toFixed(3)
} 
count--;
if(count + 1){
setTimeout(arguments.callee, frequency);
} 
},frequency)
} 
main();
} 

最终优化:利用原型链共享方法

为了进一步优化代码复用性,我们可以利用原型链共享方法。


最终优化代码如下:

 
function Opacity(el){
var node = (typeof el == "string")? document.getElementById(el) : el,
options = arguments[1] || {},
duration = options.duration || 1.0,
from = options.from || 0.0 ,
to = (options.to && options.to + "") || 0.5,
operation = -1,
init = 1;
if(to - from < 0){
operation = 1,
init = 0;
} 
var frequency = 100,
count = duration * 1000 / frequency,
detal = operation * Math.abs(to - from) /count;
this.main(node,init,detal,count,frequency);
} 
Opacity.prototype = {
main : function(node,init,detal,count,frequency){
setTimeout(function(){
if(!+"\v1"){
if(node.currentStyle.hasLayout) node.style.zoom = 1;//防止滤镜失效
node.style.filter="alpha(opacity="+ (init * 100 + detal * count * 100).toFixed(1) +")"
}else{
node.style.opacity = (init + detal * count).toFixed(3)
} 
node.innerHTML = (init + detal * count).toFixed(3)
count--;
if(count + 1){
setTimeout(arguments.callee, frequency);
} 
},frequency)
} 
} 

演示代码:


<style> .text {width:100px;height:100px;background:red;display:inline-block;} </style> <div class="text" onclick="new Opacity(this,{duration:4.0,from:0.0,to:1})"></div> <div class="text" onclick="new Opacity(this,{duration:4.0,from:1.0,to:0})"></div> 

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]


<div class="text" onclick="new Opacity(this,{duration:4.0,from:0.0,to:1})"></div>


<div class="text" onclick="new Opacity(this,{duration:4.0,from:1.0,to:0})"></div>

作者最新文章