1、引子
JavaScript
var $demo = document.getElementById('demo');
$demo.onclick = function () {
alert(1);
};
$demo.addEventListener('click', function () {
alert(2);
});
HTML
<div id="demo" style="width:100px;height:100px;background:#eee;"></div>
如上,单击方块的运行结果应该是什么呢?在高级浏览器下测试的结果是:1、2,符合预期。
通常,dom元素上的事件名称,比如“onclick、onmousedown”是与事件监听的事件名称是一一对应的,只是省略了“on”。于是:
JavaScript
var $demo = document.getElementById('demo');
$demo.onclick = function () {
$demo.style.width = '200px';
$demo.style.transition = 'all 2s';
};
$demo.ontransitionend = function () {
$demo.innerHTML = 'done';
};
$demo.addEventListener('transitionend', function () {
$demo.style.backgroundColor = '#fcc';
});
HTML
<div id="demo" style="width:100px;height:100px;background:#eee;"></div>
如上,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';
本文均为荣益互联摘自权威资料,书籍,文章,或来自网络,如有版权纠纷或违规问题,请联系我们删除。我们欢迎您的分享,谢绝直接抄袭复制。感谢…