• Bootstrap transition.js 插件


    Bootstrap transition.js 插件详解

     

    Bootstrap 自带的 JavaScript 插件的动画效果几乎都是使用 CSS 过渡实现的,而其中的 transition.js 就是为了判断当前使用的浏览器是否支持 CSS 过渡。下面先来简单了解下 CSS 过渡。

    CSS 过渡

    CSS 过渡是指在 CSS 属性发生改变时在一段时间内平滑地过渡,使用 CSS 伪类可以很方便地使用:

    a {
      color: #333;
      transition: color 1s linear;
    }
    
    a:hover {
      color: #36f;
    }

    这里给链接设置了一个 1秒的颜色过渡效果,当鼠标经过链接激活链接 :hover 状态的时候文字的颜色会从黑色平滑地变化为蓝色,鼠标移开时又平滑地变回来。

    仅仅依靠伪类来使用过渡显得太单调了,使用 JavaScript 来动态添加删除 class 才能尽情地玩弄过渡:

    /* 这是一个圆 */
    .circle {
      background-color: red;
      border-radius: 50%;
      height: 100px;
      margin-left: 220px;
      transition: transform 1s linear;
       100px;
    }
    
    /* 添加 left 类水平向左偏移 200 像素 */
    .circle.left {
      transform: translateX(-200px);
    }
    
    /* 添加 right 类水平向右偏移 200 像素 */
    .circle.right {
      transform: translateX(200px);
    }

    JavaScript 的工作就是简单的删除和添加 class:

    function toLeft() {
      $('.circle').removeClass('right').addClass('left');
    }
    
    function toRight() {
      $('.circle').removeClass('left').addClass('right');
    }

    你让它往左,它不敢往右!demo上面的例子展示了当元素状态改变或者添加了某个 class 的时候过渡就开始发生了,那么如何知道过渡什么时候结束呢?

    Transitionend 事件

    想要知道过渡什么时候结束,就要监听 transitionend 事件(事件名称全是小写字母)。

    $('.circle').one('transitionend', function() {
      alert('过渡结束啦!');
    });

    这里使用 one 方法而不是 on 方法是为了避免 transitionend 事件多次执行。one 方法添加的事件回调只会执行一次,更多信息参考官方 API

    不过这只是标准的事件名称写法,在标准之前浏览器有各自的实现方式以及不同的事件名称(比如低版本的 Chrome 和 Safari 的该事件名称就叫 webkitTransitionEnd),所以为了兼容更多的浏览器,一种比较笨拙的方式可以写成像下面这样:

    $('.circle').one('transitionend webkitTransitionEnd oTransitionEnd otransitionend', function() {});

    很长一串,而且这种写法还有一点问题!

    在这里可以看到为什么是上面这些事件名称,而没有 msTransitionEnd 之类。

    为了根据浏览器更有针对性地添加 transitionend 事件回调,而不是像上面那样一骨碌地全加上,就需要先判断一下该浏览器到底支持哪种 transitionend 事件名称,判断方法则是根据浏览器支持 CSS 过渡的属性名称而定:

    var el = document.createElement('bootstrap'); // 创建一个元素用于测试
    
    if (el.style.transition !== undefined) {
      // 判断元素的 style.transition 属性如果存在
      // 则以此类推该浏览器支持标准的 CSS transition 属性以及标准的 transitionend 事件
    } else if (el.style.WebkitTransition !== undefined) {
      // 判断元素的 style.WebkitTransition 属性如果存在
      // 则该浏览器支持替代的 webkitTransitionEnd 事件
    } else {...}

    按照当前的主流浏览器趋势总共需要判断四种不同前缀的属性名称:

    el.style.transition
    el.style.WebkitTransition
    el.style.MozTransition
    el.style.OTransition

    判断方式就是这样,废话就说到这里,直接上正牌代码,Bootstrap transition.js 内部的判断函数:

    function transitionEnd() {
      // 创建一个元素用于测试
      var el = document.createElement('bootstrap');
    
      // 将所有主流浏览器实现方式整合成一个对象,用于遍历
      // key   是属性名称
      // value 是事件名称
      var transEndEventNames = {
        WebkitTransition : 'webkitTransitionEnd',
        MozTransition    : 'transitionend',
        OTransition      : 'oTransitionEnd otransitionend',
        transition       : 'transitionend'
      };
    
      // 循环遍历上面那个对象,判断 CSS 属性是否存在
      for (var name in transEndEventNames) {
        if (el.style[name] !== undefined) {
          return { end: transEndEventNames[name] };
        }
      }
    
      return false;
    }

    执行该函数可以得到一个对象 {end: 'transitionend'} 或者 false (表示浏览器不支持 CSS 过渡),该对象的 end 属性保存着浏览器所支持的 transitionend 事件对应的名称:

    var transition = transitionEnd();

    比如我使用低版本的 Chrome 浏览器的话,那么得到的对象就是 {end: 'webkitTransitionEnd'} 这样;如果使用 IE 8 则是 false,然后就可以添加该事件的回调函数了:

    // 如果 transition 为 false 则不添加事件回调
    transition && $('.circle').one(transition.end, function() {});

    为了与 jQuery 保持一致,将该返回结果赋值到 $.support.transition 上:

    $.support.transition = transitionEnd();
    
    // 使用方式是类似的
    $.support.transition && $('.circle').one($.support.transition.end, function() {});

    EmulateTransitionEnd

    事件名称的问题基本上解决了,但是这个事件有个问题就是有时根本不会触发,这是因为属性值没有发生变化或没有绘制行为发生。要确保每次回调都会被调用,我们增加一个定时器即可:

    $.fn.emulateTransitionEnd = function(duration) {
      var called = false; // transitionend 事件是否已触发标识
      var $el = this;
      $(this).one($.support.transition.end, function () {
        called = true; // 表示已触发
      });
      var callback = function() {
        if (!called) {
          $($el).trigger($.support.transition.end); // 未触发,强制其触发
        }
      };
      setTimeout(callback, duration); // 一段时间后检测是否触发
      return this;
    };

    该方法的作用是一段时间(就是过渡持续的时间 transition-duration )过后如果 transitionend 事件没有发生则强制在该元素上触发这个事件。

    $('.circle').one($.support.transition.end, function() {});
    $('.circle').emulateTransitionEnd(1000); // 这个时间是过渡持续的时间

    这样确保过渡之后一定会有回调。到这里,基本上就差不多了,不过 $.support.transition.end 好恶心啊!能不能像添加其它事件回调一样使用事件名称字符串的形式,比如 'click',当然可以。

    自定义事件

    $(function () {
      $.support.transition = transitionEnd();
    
      // 支持过渡的时候才执行后面的代码
      if (!$.support.transition) {return;}
    
      $.event.special.bsTransitionEnd = {
        bindType: $.support.transition.end,
        delegateType: $.support.transition.end,
        handle: function (e) {
          if ($(e.target).is(this)) {
            return e.handleObj.handler.apply(this, arguments);
          }
        }
      };
    });

    添加事件回调的时候就可以像这样:

    $('.circle').one('bsTransitionEnd', function() {})
      .emulateTransitionEnd(1000);

    其它

    CSS 动画同样也有一个 animationend 事件,同时还有 animationstart 和 animationiteration 事件,可以参考这种方式自己写一个。

    参考资料

     
     
    标签: js
  • 相关阅读:
    November 13th 2016 Week 47th Sunday The 1st Day
    November 12th 2016 Week 46th Saturday
    November 11th 2016 Week 46th Friday
    November 10th 2016 Week 46th Thursday
    November 9th 2016 Week 46th Wednesday
    November 8th 2016 Week 46th Tuesday
    windows 7文件共享方法
    Win7无线网络共享设置方法
    常量指针和指针常量
    如何查找局域网的外网ip
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4252619.html
Copyright © 2020-2023  润新知