-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheffects.js
More file actions
142 lines (117 loc) · 3.49 KB
/
effects.js
File metadata and controls
142 lines (117 loc) · 3.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/**
* @module effects
*/
// 默认样式
const styles = document.documentElement.style;
// Animation 映射表
const ANIMATION_MAPS = [
['animation', 'animationend'],
['WebkitAnimation', 'webkitAnimationEnd'],
['MozAnimation', 'mozAnimationEnd'],
['OAnimation', 'oAnimationEnd'],
['msAnimation', 'MSAnimationEnd'],
['KhtmlAnimation', 'khtmlAnimationEnd']
];
// Transition 映射表
const TRANSITION_MAPS = [
['transition', 'transitionend'],
['WebkitTransition', 'webkitTransitionEnd'],
['MozTransition', 'mozTransitionEnd'],
['OTransition', 'oTransitionEnd'],
['msTransition', 'MSTransitionEnd'],
['KhtmlTransition', 'khtmlTransitionEnd']
];
/**
* @function detect
* @param {object} maps
*/
function detect(maps) {
for (const [prop, event] of maps) {
if (prop in styles) {
return [prop, event];
}
}
}
// Animation
const [ANIMATION, ANIMATION_END] = detect(ANIMATION_MAPS);
// Transition
const [TRANSITION, TRANSITION_END] = detect(TRANSITION_MAPS);
/**
* @function toMs
* @param {string} value
*/
function toMs(value) {
return Number(value.slice(0, -1).replace(',', '.')) * 1000;
}
/**
* @function calcTimeout
* @param {Array} delays
* @param {Array} durations
*/
function calcTimeout(delays, durations) {
while (delays.length < durations.length) {
delays = delays.concat(delays);
}
const times = durations.map((duration, index) => toMs(duration) + toMs(delays[index]));
// 获取最大时长
return Math.max.apply(null, times);
}
/**
* @function toArray
* @param {any} value
*/
function toArray(value) {
return value ? value.split(', ') : [];
}
/**
* @function calcEffects
* @param {HTMLElement} node
*/
function calcEffects(node) {
const styles = window.getComputedStyle(node);
const transitioneDelays = toArray(styles.getPropertyValue(TRANSITION + '-delay'));
const transitionDurations = toArray(styles.getPropertyValue(TRANSITION + '-duration'));
const transitionTimeout = calcTimeout(transitioneDelays, transitionDurations);
const animationDelays = toArray(styles.getPropertyValue(ANIMATION + '-delay'));
const animationDurations = toArray(styles.getPropertyValue(ANIMATION + '-duration'));
const animationTimeout = calcTimeout(animationDelays, animationDurations);
const timeout = Math.max(transitionTimeout, animationTimeout);
const effect = timeout > 0 ? (transitionTimeout > animationTimeout ? TRANSITION : ANIMATION) : null;
const count = effect ? (effect === TRANSITION ? transitionDurations.length : animationDurations.length) : 0;
return { effect, count, timeout };
}
/**
* @function onEffectsEnd
* @param {HTMLElement} node
* @param {Function} callback
* @see https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/transition-util.js
*/
export default function onEffectsEnd(node, callback) {
// 不支持动画
if (!ANIMATION && !TRANSITION) return callback();
const { count, effect, timeout } = calcEffects(node);
// 没有动画
if (!effect) return callback();
let ended = 0;
// 防止有些动画没有触发结束事件
const timer = setTimeout(function () {
if (ended < count) {
end();
}
}, timeout + 1);
const event = effect === TRANSITION ? TRANSITION_END : ANIMATION_END;
const end = () => {
clearTimeout(timer);
node.removeEventListener(event, onEnd);
callback();
};
const onEnd = function (e) {
if (e.target === node) {
if (++ended >= count) {
end();
}
}
};
// 监听动画完成事件
node.addEventListener(event, onEnd);
}