Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bootstrap源码解读——transition.js #15

Open
jiangshanmeta opened this issue Jul 1, 2017 · 0 comments
Open

bootstrap源码解读——transition.js #15

jiangshanmeta opened this issue Jul 1, 2017 · 0 comments

Comments

@jiangshanmeta
Copy link
Owner

bootstrap是一个出名的前端框架,它预制了一些常见的js插件。它相当多功能都依赖这里要介绍的是transition.js,它的作用是对css3的过渡的兼容处理。

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 
}

这一段是对transitionend事件做兼容,如果浏览器支持各种形式的transitionend,就以对象的形式返回兼容后的结果,否则返回false,表明不支持transitionend事件,另一层意思就是不支持CSS3过渡。

之前我收集过一个类似功能的函数

function whichTransitionEvent(){  
    var t;  
    var el = document.createElement('p');  
    var transitions = {  
      'transition':'transitionend',  
      'OTransition':'oTransitionEnd',  
      'MozTransition':'mozTransitionEnd',  
      'WebkitTransition':'webkitTransitionEnd',  
      'MsTransition':'msTransitionEnd'  
    }  
    for(t in transitions){  
        if( el.style[t] !== undefined ){  
            return transitions[t];  
        }  
    }  
}

为jQuery添加事件bsTransitionEnd

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

这里把最终的transitionend事件挂到了$.support.transition上,相当于一个缓存。然后是一段让我很纠结的代码,$.event.special.bsTransitionEnd是干啥的的?搜索了一下中文文章发现虽然有提的但是完全不靠谱(这么不靠谱的文章竟然有一堆转载),然后我就在stackoverflow上找到了答案

它的意思是这里的bsTransitionEnd相当于兼容后的transitionend事件的别名。为什么要取一个别名而不是直接使用兼容后的transitionend呢?因为怕你我手抖移除transitionend事件的时候不传具体的回调而是直接移除整个事件然后bootstrap插件的回调也一并移除然后报bug。算是为了代码的健壮性吧。

模拟transitionend事件

还有一段代码:

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

$.fn.emulateTransitionEnd,看这个形式是直接挂到了jquery的prototype上了。看函数名猜测这一段代码是为了模拟transitionend事件的。不理解作者想干啥,但是源码中给了一个连接,于是我就找来这篇博客看,原作者是这么说的:

Be aware that sometimes this event doesn’t fire, usually in the case when properties don’t change or a paint isn’t triggered. To ensure we always get a callback, let’s set a timeout that’ll trigger the event manually.

换句话说作者是为了保证即使没有过渡也要触发transitionend事件保证相应的回调能够执行。

具体实现上called变量保存的是transitionend是否被触发,这个变量的存在是为了保证transitionend只触发一次。可能触发多次的情况一个是transition多个属性会触发多个transitionend事件,另一个是真的transitionend事件已经触发,不需要模拟transitionend。

顺便提一句,上面那篇文章提到了强制重绘,有一句话我觉得很好

This will work in most browsers, but I’ve had occasions in Android where this hasn’t been enough. The alternative is to either use timeouts, or by toggling a class name.

transition.js内容不多,就只有三块,但是却是bootstap js插件非常重要的一环,后面只要用到css过渡的插件都依赖transition.js。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant