Bootstrap源码:transition.js

bootstrap大量使用了css的过渡实现动画,所以监听动画结束事件,并执行回调函数十分关键。浏览器对css动画的支持不同,有的不支持css过渡,有的即使支持过渡,但是不一定会触发动画结束事件,即使良好支持过渡的浏览器,不同的厂商,对应的结束事件类型不同,transition.js的作用就是:
1. 统一不同浏览器对css过渡结束事件的支持;
2. 即使浏览器不触发结束事件,也能保证回调函数执行。

transitionEnd()

function transitionEnd() {
    var el = document.createElement('bootstrap')

    var transEndEventNames = {
      WebkitTransition : 'webkitTransitionEnd',
      MozTransition    : 'transitionend',
      OTransition      : 'oTransitionEnd otransitionend',
      transition       : 'transitionend'
    }

    for (var name in transEndEventNames) {
      if (el.style[name] !== undefined) {
        return { end: transEndEventNames[name] }
      }
    }

    return false // explicit for ie8 (  ._.)
  }

该段比较简单,比较陌生的是createElement('bootstrap')然后利用这个元素的style属性去判断是否支持动画结束事件属性的方式,原来html还可以这么玩。。为什么药这么做,我觉得可能的原因是这里仅仅是要判断浏览器的DOM是否支持某个DOM元素的属性,并不需要调整DOM结构,所以用这种自定义的元素的代价会比标准的html元素代价小。。。

emulateTransitionEnd

$.fn.emulateTransitionEnd = function (duration) {
    var called = false
    var $el = this
    $(this).one('bsTransitionEnd', function () { called = true })
    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
    setTimeout(callback, duration)
    return this
  }

这个函数添加到了jquery的原型上,这样每个jquery对象就都能调用了,它的作用是用来模拟动画结束事件,并在duration时间间隔后,调用回调函数。

关键代码一

$(this).one('bsTransitionEnd', function () { called = true })

给当前的动画元素再绑定一次动画结束事件处理,假如浏览器支持,那么在bsTransitionEnd事件触发后,called将会变为true。

关键代码二

var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)

定义了一个计时器,在duration之后执行callback,callback里面判断,当called为false时,则人为触发bsTransitionEnd事件。假如浏览器支持动画结束事件,callback里面的人为触发就不会执行。


不过这里也有一个问题,就是这个duration的时间假如比动画运行的时间短的话,那么人为的触发就会先执行,不管浏览器支不支持css动画结束事件,所以要正确地使用这个组件,duration必须大于等于css transition中定义的时间,最后分析完剩余代码之后,可以看下bootstrap的组件是如何定义transition的时间跟duration的。

最后一部分代码:

$(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)
      }
    }
  })

关键代码一


$.support.transition = transitionEnd()

这样就可以方便地判断当前是否支持过渡动画结束事件了。if($.support.transition) { ... }


关键代码二


$.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)
      }
    }

这个暂时只能认为是固定的写法了,用来自定义事件,等将来学过jquery的源码后,自然就理解了吧。


最后,这个组件怎么用,bootstrap里面的每个组件都有例子,如alert.js中的close方法的最后:


$.support.transition && $parent.hasClass('fade') ?
      $parent
        .one('bsTransitionEnd', removeElement)
        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
      removeElement()

首先用$.support.transition判断是否支持过渡结束事件,不支持的话,直接调用回调函数,否则对bsTransitionEnd绑定一次处理器,就是要执行的回调函数,同时为了保证在动画结束事件不触发时,依然能够执行回调函数,调用了emulateTransitionEnd函数。

最最后看下Alert.TRANSITION_DURATION跟css中的transition时间:

Alert.TRANSITION_DURATION = 150
.fade {
  opacity: 0;
  -webkit-transition: opacity .15s linear;
  -o-transition: opacity .15s linear;
  transition: opacity .15s linear;
}



这两个时间是一样的!



你可能感兴趣的:(bootstrap,bootstrap源码)