1、引子
如上,单击方块的运行结果应该是什么呢?在高级浏览器下测试的结果是:1、2,符合预期。
通常,dom元素上的事件名称,比如“onclick、onmousedown”是与事件监听的事件名称是一一对应的,只是省略了“on”。于是:
如上,ontransitionend
是监听 css3 中 transition
过渡结束的事件,相关链接可以阅读参考链接。实际运行结果是,#demo
元素内并未如期的出现 done 内容。
2、折腾
于是尝试用驼峰形式来书写,如 onTransitionEnd、onWebkitTransitionEnd 都没有达到预期的结果。为什么要做这个尝试?因为有这样的事件名称:DOMContentLoaded。并且,奇葩的是,这个事件名称虽然是监听 document 的,但是也无法使用 document.onDOMContentLoaded 来监听。但 "onDOMContentLoaded" in document 却返回 true,让人摸不着头脑。
因此,尝试使用 in 操作符来检测元素是否含有该事件监听方法存在。
- "onDOMContentLoaded" in document; // => true
- "ontransitionend" in document.body; // => false
- "onTransitionEnd" in document.body; // => false
- "onWebkitTransitionEnd" in document.body; // => false
上面结果的出现,倍感吃惊。当我们尝试在 window
对象上进行 in
检测时:
- "ontransitionend" in window; // => true
真调皮的。当我拿着这段欣喜若狂的代码去火狐下检测时:
- "ontransitionend" in window; // => false
- "ontransitionend" in document;; // => false
- "ontransitionend" in document.body;; // => false
- "onMozTransitionEnd" in window;; // => false
- "onMozTransitionEnd" in document;; // => false
- "onMozTransitionEnd" in document.body;; // => false
火狐更让我吃惊。但是火狐确实可以用 document.addEventListener
来监听到 transitionend
事件的,却无法检测出来。
于是,找来了 zepto 这个脚本库来参考,才出这么一个蹩脚的检测方案:
先检测 transition-property 这个 css 属性的私有前缀,然后添加到 transitionend 前面去(详细方法见下一节)。确实可以这样检测,但多多少少让人觉得有些失真,css 属性的私有前缀和 JS 事件的私有前缀,虽然有联系,但他们是没有交集的。比如浏览器率先支持了css3 的标准属性,但有私有前缀,但并不能说明,此时浏览器已经支持该 css3 的事件结束回调!?
不过怎样吧,这也算是绕了弯路,多少都已经到达目的地了。
3、私有前缀检测工具
3.1、检测 css3 私有前缀
- /**
- * 获取有浏览器前缀的CSS3名称
- * @param {String} standard 标准的CSS3属性
- * @returns {String|null} 私有CSS3属性
- *
- * @example
- * compatible.css3('border-start');
- * // => "-webkit-border-start"
- */
- css3: function (standard) {
- var cssKey = null;
- var find = !1;
- standard = _toSepString(standard.trim().replace(regCss3, ''));
- dato.each(css3Prefixs, function (index, prefix) {
- cssKey = prefix ? prefix + '-' + standard : standard;
- var testCssKey = fixCss[cssKey] ? fixCss[cssKey]: cssKey;
- if (_toHumbString(testCssKey) in p.style) {
- find = !0;
- return !1;
- }
- });
- return find ? cssKey : null;
- }
原理很简单,遍历一下私有前缀 ['', '-webkit', '-moz', '-ms']
,使用 in
操作符在 style
对象里进行匹配,返回最先匹配到的,否则返回 null。
3.2、检测 html5 私有前缀
- /**
- * 获取有浏览器前缀的方法名称
- * @param {String} standard 标准属性、方法名称
- * @param {Object} parent 标准方法父级
- * @param {Boolean} [isEventType=false] 是否为事件类型
- * @returns {String} 私有属性、方法名称
- *
- * @example
- * compatible.html5('audioContext', window);
- * // => "webkitAudioContext"
- */
- html5: function (standard, parent, isEventType) {
- var html5Key = null;
- var find = !1;
- if(isEventType){
- standard = standard.replace(regOn, '');
- }
- dato.each(html5Prefixs, function (index, prefix) {
- html5Key = isEventType ?
- (prefix + standard ):
- (prefix ? prefix + _toUpperCaseFirstLetter(standard) : standard);
- if ((isEventType ? 'on':'') + html5Key in parent) {
- find = !0;
- return !1;
- }
- });
- return find ? html5Key : undefined;
- }
html5 检测要稍微多做一步,需要指定父级对象和是否为事件名称(事件名称都带有 on 前缀)。原理也很简单,也是遍历 ['', 'webkit', 'moz', 'ms', 'MS']
操作。
最后,检测出 transitionend 的私有方法:
- var css = 'transition-property';
- var transitionendEventPrefix = compatible.css3(css).replace(css, '').replace(/-/g, '');
- var transitionendEventType = transitionendEventPrefix ? transitionendEventPrefix + 'TransitionEnd' : 'transitionend';