ant-design-vue/components/_util/css-animation/index.js

182 lines
4.6 KiB
JavaScript
Raw Normal View History

2018-12-12 22:09:30 +08:00
// https://github.com/yiminghe/css-animation 1.5.0
2019-01-12 11:33:27 +08:00
import Event from './Event';
import classes from 'component-classes';
import { requestAnimationTimeout, cancelAnimationTimeout } from '../requestAnimationTimeout';
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
const isCssAnimationSupported = Event.endEvents.length !== 0;
const capitalPrefixes = [
'Webkit',
2018-02-04 11:08:04 +08:00
'Moz',
'O',
// ms is special .... !
2019-01-12 11:33:27 +08:00
'ms',
];
const prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', ''];
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
function getStyleProperty(node, name) {
2018-02-04 11:08:04 +08:00
// old ff need null, https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
2019-01-12 11:33:27 +08:00
const style = window.getComputedStyle(node, null);
let ret = '';
2018-02-04 11:08:04 +08:00
for (let i = 0; i < prefixes.length; i++) {
2019-01-12 11:33:27 +08:00
ret = style.getPropertyValue(prefixes[i] + name);
2018-02-04 11:08:04 +08:00
if (ret) {
2019-01-12 11:33:27 +08:00
break;
2018-02-04 11:08:04 +08:00
}
}
2019-01-12 11:33:27 +08:00
return ret;
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
function fixBrowserByTimeout(node) {
2018-02-04 11:08:04 +08:00
if (isCssAnimationSupported) {
2019-01-12 11:33:27 +08:00
const transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0;
const transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0;
const animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0;
const animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0;
const time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay);
2018-02-04 11:08:04 +08:00
// sometimes, browser bug
node.rcEndAnimTimeout = setTimeout(() => {
2019-01-12 11:33:27 +08:00
node.rcEndAnimTimeout = null;
2018-02-04 11:08:04 +08:00
if (node.rcEndListener) {
2019-01-12 11:33:27 +08:00
node.rcEndListener();
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
}, time * 1000 + 200);
2018-02-04 11:08:04 +08:00
}
}
2019-01-12 11:33:27 +08:00
function clearBrowserBugTimeout(node) {
2018-02-04 11:08:04 +08:00
if (node.rcEndAnimTimeout) {
2019-01-12 11:33:27 +08:00
clearTimeout(node.rcEndAnimTimeout);
node.rcEndAnimTimeout = null;
2018-02-04 11:08:04 +08:00
}
}
const cssAnimation = (node, transitionName, endCallback) => {
2019-01-12 11:33:27 +08:00
const nameIsObj = typeof transitionName === 'object';
const className = nameIsObj ? transitionName.name : transitionName;
const activeClassName = nameIsObj ? transitionName.active : `${transitionName}-active`;
let end = endCallback;
let start;
let active;
const nodeClasses = classes(node);
2018-02-04 11:08:04 +08:00
if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') {
2019-01-12 11:33:27 +08:00
end = endCallback.end;
start = endCallback.start;
active = endCallback.active;
2018-02-04 11:08:04 +08:00
}
if (node.rcEndListener) {
2019-01-12 11:33:27 +08:00
node.rcEndListener();
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
node.rcEndListener = e => {
2018-02-04 11:08:04 +08:00
if (e && e.target !== node) {
2019-01-12 11:33:27 +08:00
return;
2018-02-04 11:08:04 +08:00
}
if (node.rcAnimTimeout) {
2019-01-12 11:33:27 +08:00
cancelAnimationTimeout(node.rcAnimTimeout);
node.rcAnimTimeout = null;
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
clearBrowserBugTimeout(node);
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
nodeClasses.remove(className);
nodeClasses.remove(activeClassName);
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
Event.removeEndEventListener(node, node.rcEndListener);
node.rcEndListener = null;
2018-02-04 11:08:04 +08:00
// Usually this optional end is used for informing an owner of
// a leave animation and telling it to remove the child.
if (end) {
2019-01-12 11:33:27 +08:00
end();
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
};
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
Event.addEndEventListener(node, node.rcEndListener);
2018-02-04 11:08:04 +08:00
if (start) {
2019-01-12 11:33:27 +08:00
start();
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
nodeClasses.add(className);
2018-02-04 11:08:04 +08:00
node.rcAnimTimeout = requestAnimationTimeout(() => {
2019-01-12 11:33:27 +08:00
node.rcAnimTimeout = null;
nodeClasses.add(activeClassName);
2018-02-04 11:08:04 +08:00
if (active) {
2019-01-12 11:33:27 +08:00
requestAnimationTimeout(active, 0);
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
fixBrowserByTimeout(node);
2018-02-04 11:08:04 +08:00
// 30ms for firefox
2019-01-12 11:33:27 +08:00
}, 30);
2018-02-04 11:08:04 +08:00
return {
2019-01-12 11:33:27 +08:00
stop() {
2018-02-04 11:08:04 +08:00
if (node.rcEndListener) {
2019-01-12 11:33:27 +08:00
node.rcEndListener();
2018-02-04 11:08:04 +08:00
}
},
2019-01-12 11:33:27 +08:00
};
};
2018-02-04 11:08:04 +08:00
cssAnimation.style = (node, style, callback) => {
if (node.rcEndListener) {
2019-01-12 11:33:27 +08:00
node.rcEndListener();
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
node.rcEndListener = e => {
2018-02-04 11:08:04 +08:00
if (e && e.target !== node) {
2019-01-12 11:33:27 +08:00
return;
2018-02-04 11:08:04 +08:00
}
if (node.rcAnimTimeout) {
2019-01-12 11:33:27 +08:00
cancelAnimationTimeout(node.rcAnimTimeout);
node.rcAnimTimeout = null;
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
clearBrowserBugTimeout(node);
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
Event.removeEndEventListener(node, node.rcEndListener);
node.rcEndListener = null;
2018-02-04 11:08:04 +08:00
// Usually this optional callback is used for informing an owner of
// a leave animation and telling it to remove the child.
if (callback) {
2019-01-12 11:33:27 +08:00
callback();
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
};
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
Event.addEndEventListener(node, node.rcEndListener);
2018-02-04 11:08:04 +08:00
node.rcAnimTimeout = requestAnimationTimeout(() => {
for (const s in style) {
if (style.hasOwnProperty(s)) {
2019-01-12 11:33:27 +08:00
node.style[s] = style[s];
2018-02-04 11:08:04 +08:00
}
}
2019-01-12 11:33:27 +08:00
node.rcAnimTimeout = null;
fixBrowserByTimeout(node);
}, 0);
};
2018-02-04 11:08:04 +08:00
cssAnimation.setTransition = (node, p, value) => {
2019-01-12 11:33:27 +08:00
let property = p;
let v = value;
2018-02-04 11:08:04 +08:00
if (value === undefined) {
2019-01-12 11:33:27 +08:00
v = property;
property = '';
2018-02-04 11:08:04 +08:00
}
2019-01-12 11:33:27 +08:00
property = property || '';
capitalPrefixes.forEach(prefix => {
node.style[`${prefix}Transition${property}`] = v;
});
};
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
cssAnimation.isCssAnimationSupported = isCssAnimationSupported;
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
export { isCssAnimationSupported };
2018-02-04 11:08:04 +08:00
2019-01-12 11:33:27 +08:00
export default cssAnimation;