Evan You
8 years ago
7 changed files with 221 additions and 124 deletions
@ -0,0 +1,111 @@ |
|||
import { inBrowser } from 'core/util/index' |
|||
import { isIE9 } from 'web/util/index' |
|||
import { remove } from 'shared/util' |
|||
import { addClass, removeClass } from './class-util' |
|||
|
|||
export const hasTransition = inBrowser && !isIE9 |
|||
const TRANSITION = 'transition' |
|||
const ANIMATION = 'animation' |
|||
|
|||
// Transition property/event sniffing
|
|||
export let transitionProp = 'transition' |
|||
export let transitionEndEvent = 'transitionend' |
|||
export let animationProp = 'animation' |
|||
export let animationEndEvent = 'animationend' |
|||
if (hasTransition) { |
|||
/* istanbul ignore if */ |
|||
if (window.ontransitionend === undefined && |
|||
window.onwebkittransitionend !== undefined) { |
|||
transitionProp = 'WebkitTransition' |
|||
transitionEndEvent = 'webkitTransitionEnd' |
|||
} |
|||
if (window.onanimationend === undefined && |
|||
window.onwebkitanimationend !== undefined) { |
|||
animationProp = 'WebkitAnimation' |
|||
animationEndEvent = 'webkitAnimationEnd' |
|||
} |
|||
} |
|||
|
|||
const raf = (inBrowser && window.requestAnimationFrame) || setTimeout |
|||
export function nextFrame (fn: Function) { |
|||
raf(() => { |
|||
raf(fn) |
|||
}) |
|||
} |
|||
|
|||
export function addTransitionClass (el: any, cls: string) { |
|||
(el._transitionClasses || (el._transitionClasses = [])).push(cls) |
|||
addClass(el, cls) |
|||
} |
|||
|
|||
export function removeTransitionClass (el: any, cls: string) { |
|||
if (el._transitionClasses) { |
|||
remove(el._transitionClasses, cls) |
|||
} |
|||
removeClass(el, cls) |
|||
} |
|||
|
|||
export function whenTransitionEnds (el: Element, cb: Function) { |
|||
const { type, timeout, propCount } = getTransitionInfo(el) |
|||
if (!type) return cb() |
|||
const event = type === TRANSITION ? transitionEndEvent : animationEndEvent |
|||
let ended = 0 |
|||
const end = () => { |
|||
el.removeEventListener(event, onEnd) |
|||
cb() |
|||
} |
|||
const onEnd = () => { |
|||
if (++ended >= propCount) { |
|||
end() |
|||
} |
|||
} |
|||
setTimeout(() => { |
|||
if (ended < propCount) { |
|||
end() |
|||
} |
|||
}, timeout + 1) |
|||
el.addEventListener(event, onEnd) |
|||
} |
|||
|
|||
const transformRE = /\b(transform|all)(,|$)/ |
|||
|
|||
export function getTransitionInfo (el: Element): { |
|||
type: ?string, |
|||
propCount: number, |
|||
timeout: number |
|||
} { |
|||
const styles = window.getComputedStyle(el) |
|||
const transitionProps = styles[transitionProp + 'Property'] |
|||
const transitioneDelays = styles[transitionProp + 'Delay'].split(', ') |
|||
const transitionDurations = styles[transitionProp + 'Duration'].split(', ') |
|||
const animationDelays = styles[animationProp + 'Delay'].split(', ') |
|||
const animationDurations = styles[animationProp + 'Duration'].split(', ') |
|||
const transitionTimeout = getTimeout(transitioneDelays, transitionDurations) |
|||
const animationTimeout = getTimeout(animationDelays, animationDurations) |
|||
const timeout = Math.max(transitionTimeout, animationTimeout) |
|||
const type = timeout > 0 |
|||
? transitionTimeout > animationTimeout |
|||
? TRANSITION |
|||
: ANIMATION |
|||
: null |
|||
return { |
|||
type, |
|||
timeout, |
|||
propCount: type |
|||
? type === TRANSITION |
|||
? transitionDurations.length |
|||
: animationDurations.length |
|||
: 0, |
|||
hasTransform: type === TRANSITION && transformRE.test(transitionProps) |
|||
} |
|||
} |
|||
|
|||
function getTimeout (delays: Array<string>, durations: Array<string>): number { |
|||
return Math.max.apply(null, durations.map((d, i) => { |
|||
return toMs(d) + toMs(delays[i]) |
|||
})) |
|||
} |
|||
|
|||
function toMs (s: string): number { |
|||
return Number(s.slice(0, -1)) * 1000 |
|||
} |
Loading…
Reference in new issue