Ruby's Louvre

每天学习一点点算法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

javascript的可控式透明特效

透明特效是script.aculo.us提到的特效中最简单的特效之一。既然是特效,必须涉及时间与空间的概念。时间我们可以用setTimeout与setInterval,个人比较喜欢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();
}

我们来试一下最简单的淡入特效,就是把node.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();
}
<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。我们是通过短路运算符来决定是否使用默认参数还是我们传入的参数,但在javascript中,数字0甚至0.0都会自动转换为false。因此在第个例子,如果我们在to中传入0,它永远不会用到这个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)
  }
}
<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>

如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码

posted on   司徒正美  阅读(3588)  评论(10编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示