我用过树行者 API https://developer.mozilla.org/en/docs/Web/API/TreeWalker遍历原始节点(根)和所有子节点(仅限元素),过滤掉没有过渡的元素,并收集过渡属性queue
(fiddle http://jsfiddle.net/7q8psw14/13/)。正如你所看到的,我已经解决了之间的时差complete-div
and complete-p
,他们现在(几乎 - 几毫秒)同时开火。
有两个警告,我没有解决方法:
- 如果存在通过不同方式触发的转换,对于
示例一是通过添加触发的
.visible
to the div
,以及
其他通过添加.invisible
,它们都会被添加到queue
。该事件永远不会触发,因为queue
永远不会空 - 我不知道如何解决这个问题。
- 如果存在快捷方式属性的转换(
padding
为了
示例),多个transitionend
事件可能会被触发,transition-property
, 例如padding-top
, padding-right
等等...这个
将导致数组很快变空splice(-1, 1)
从数组末尾删除项目。我曾有一个解决方法 http://jsfiddle.net/7q8psw14/11/, 但
这可能会导致问题,因为它可能会删除queue
。最好的解决方法是不要通过快捷方式进行转换
特性。
TreeWalker 的代码基于 Ban Nadel 的 -使用 TreeWalker 在 DOM 中查找 HTML 注释节点 http://www.bennadel.com/blog/2607-finding-html-comment-nodes-in-the-dom-using-treewalker.htm.
最后是代码:
(function ($) {
$.event.special.transitionsComplete = {
setup: function (data, namespaces, eventHandle) {
var TRANSITION_PROPERTY = 'transition-property';
var TRANSITION_DURATION = 'transition-duration';
var root = this;
var queue = [];
var $node = $(this);
function filter(node) { // filter for treeWalker
/*** filters transitions which are a string with one '0s'. If more then '0s' is defined it will be catched when creating the queue ***/
var computedDuration = window.getComputedStyle(node, null)
.getPropertyValue(TRANSITION_DURATION);
return computedDuration === '0s' ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_ACCEPT;
}
filter.acceptNode = filter; // for webkit and firefox
/** create the treeWalker to traverse only elements **/
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filter, false);
/** traverse all elements using treeWalker.nextNode(). First node is the root **/
do {
var style = window.getComputedStyle(treeWalker.currentNode, null);
var computedProps = style.getPropertyValue(TRANSITION_PROPERTY).split(', ');
var computedDurations = style.getPropertyValue(TRANSITION_DURATION).split(', ');
/** push all props with duration which is not 0s **/
computedDurations.forEach(function (duration, index) {
duration !== '0s' && queue.push(computedProps[index]);
});
} while (treeWalker.nextNode()); // iterate until no next node
// no transitions, fire (almost) immediately
if (queue.length === 0) {
setTimeout(function () {
$node.trigger('transitionsComplete');
}, 5);
return; // return out of the function to skip the transitions block
}
// there are transitions
$node.on('webkitTransitionEnd.x transitionend.x', function (e) {
var propertyName = e.originalEvent.propertyName;
var indexOfProp = queue.indexOf(propertyName);
queue.splice(indexOfProp, 1);
if (queue.length < 1) {
console.log('Transitions Complete');
$node.trigger('transitionsComplete');
}
});
},
teardown: function (namespaces) {
$(this).off('.x');
}
};
})(jQuery);