正在加载中

最后更新于 2018年12月26日

根据传统,我们先修复一下上一章的bug。

有两个bug:

  1. 当同步动画和队列动画同时存在的时候,队列动画会触发多次。
  2. 如果同步动画中,两个值或者多个值相差太多就无法完整运行。

原因:

主要原因是因为我们在定时器中使用了for语句,然后是同步动画的时候,假设是两个动画要同时运行,那么就会触发两个if判断,然后这两个if判断到最后都会运行一次setAttr()或者setOpacity()的方法,而这两个的方法里面都有if(obj.fn != undefined) obj.fn(); 这个语句,fn本身就是队列动画,那么就会导致触发多次。

而无法完成运行是因为,假设宽度要到300,高度101,元素本身高度是100,那么这样设置,高度会先到达目标点,从而触发setAttr()方法,这个方法里面有clearInterval(element.timer);清除超时调用,这样就导致超时调用中的宽度还在递增的时候就被强制停止了。

解决办法:

我们可以不让这个setAttr()或者setOpacity()的方法运行fn和清除超时调用。

先在超时调用里面创建一个判断元素,判断动画是否已经完成,如果完成,我们再运行fn和清理超时调用。

于是:

 element.timer = setInterval(function() {
     var flage = true;
     for (var i in mul) {
         attr = i == 'x' ? 'left' : i == 'y' ? 'top' :
             i == 'w' ? 'width' : i == 'h' ? 'height' :
             i == 'o' ? 'opacity' : i != undefined ? i : 'left';
         end = mul[i];

         if (type == 'buffer') {
             step = attr == 'opacity' ? (end - getOpacity()) / speed :
                 (end - parseInt(getStyle(element, attr))) / speed;
             step = (step > 0) ? Math.ceil(step) : Math.floor(step);
         }
         if (attr == 'opacity') {
             if (step == 0) {
                 setOpacity();
             } else if (step > 0 && Math.abs(getOpacity() - end) <= step) {
                 setOpacity();
             } else if (step < 0 && (getOpacity() - end) <= Math.abs(step)) {
                 setOpacity();
             } else {
                 var temp = getOpacity();
                 element.style.opacity = (temp + step) / 100;
                 element.style.filter = 'alpha(opacity=' + (temp + step) + ')'
             }
             if (end != getOpacity()) flage = false;
         } else {
             if (step == 0) {
                 setAttr();
             } else if (step > 0 && Math.abs(parseInt(getStyle(element, attr)) - end) <= step) {
                 setAttr();
             } else if (step < 0 && (parseInt(getStyle(element, attr)) - end) <= Math.abs(step)) {
                 setAttr();
             } else {
                 element.style[attr] = parseInt(getStyle(element, attr)) + step + 'px';
             }
             if (end != parseInt(getStyle(element, attr))) flage = false;
         };
     };
     if (flage) {
         clearInterval(element.timer);
         if (obj.fn != undefined) obj.fn();
     }

 }, time);

 function setAttrsetAttr() {
     element.style[attr] = end + 'px';
 }

 function setOpacity() {
     element.style.opacity = parseInt(end) / 100;
     element.style.filter = 'alpha(opacity=' + parseInt(end) + ')';
 }
 function getOpacity() {
      if (system.ie <= 8) {
          var op = getStyle(element, 'filter');
          var s = [];
          if (op.match(/opacity=([\d]+)/)) {
              s = op.match(/\=([\d]+)/);
          } else {
              throw new Error('ie8一下没有获取到filter中的opacity值');
          }
          return parseInt(s[1]);
      } else {
          return parseFloat(getStyle(element, 'opacity')) * 100;
      }
}

先创建一个flage元素,默认为true,然后将setAttr()和setOpacity()方法中运行fn和清理超时调用删除。

在opcacity和attr的if判断中,在他们if运算完后,再来判断end值是否不等于当前元素即时获取的值,如果不等于让flage等于false。

当for(var i in mul)语句都循环完毕后,说明第一次已经运行完毕了,加上我们并没有清理超时调用,这时候便会再次运行,我们在这个for语句后面判断,判断flage是否为true的时候,如果是true,说明当前元素的值已经等于end了,那么就运行fn和清理超时调用。

这里就解决了fn多次调用的问题,实际上连同步动画相差太大的问题也解决了。

这里就有疑问了,同步动画的时候,for语句会循环,那么应该是同时都会触发 if (end != parseInt(getStyle(element, attr))) flage = false;这个判断的,按照js代码的先后顺序,如果前一个判断为false,后一个为true,那么后一个的值应该会覆盖前一个的。

但是实际上并不是这样的,for语句循环的两个因为处理速度快,基本上算是同时运行,这里我们假设宽度要到300,高度101,元素本身高度是100,高度的if判断一下子就完成了,因为他只要+1,而宽度300要经过三次if判断,这里高度就会先于宽度判断完flage的值,然后宽度再判断,再重新赋值给flage。

这里就会有快慢之分,慢的flage赋值永远是最后的,这样只有慢的那个也完成了,才会触发清理超时调用和运行fn。

于是完美解决上面上个问题。

展示菜单:

给个人设置添加动画效果:

调用代码:

//个人设置
$('#header .nav-confin').hover(function() {
    $(this).css('background-color', '#2b2c2e');
    $('#header .nav-menu').animation({
        'mul': {
            'o': 100,
            'h': 120
        }
    });
}, function() {
    $(this).css('background-color', 'transparent');
    $('#header .nav-menu').animation({
        'mul': {
            'o': 0,
            'h': 0
        }
    });
});
$('#header .menu-li').hover(function() {
    $(this).css('background-color', '#2b2c2e');
}, function() {
    $(this).css('background-color', 'transparent');
});

直接使用同步动画,不用再设置css的height了。

效果图:

  • weixiao kaixin tushetou jingkong deyi fanu liezui liuhan daku ganga bishi nanguo lihai qian yiwen numu tu yi haixiu se fadai minyan hehe henkaixin huaji biyiyan kuanghan maimeng shui xiaku penqi zhangzui pen aini ye niu laji ok chigua renshi kongbu shuai xiaoxiese touxiao huaixiao jingnu chihuai kaisang xiaoku koubi zhuangbi lianhong kanbujian shafa zhijing xiangjiao dabian yaowan redjing lazhu rizhi duocang chixigua hejiu xixi xiaopen goukun xiaobuchu shenme wusuowei guancha lajing chouyan xiaochi bie zhadanzui zhadanxiao
  1. 1

    发表于:
    来自 QQ浏览器 6 in Android O

    4

  2. 11

    发表于:
    来自 Google Chrome 70 in windows 10

    11

登录