UNPKG

16.2 kBJavaScriptView Raw
1import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
2import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
3import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
4import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
5var _excluded = ["component", "componentProps", "interval", "duration", "delay", "type", "animConfig", "ease", "leaveReverse", "forcedReplay", "animatingClassName", "onEnd", "appear"];
6import { useRef, useMemo, useLayoutEffect, useEffect, useState, createElement, cloneElement, forwardRef } from 'react';
7import { findDOMNode } from 'react-dom';
8import TweenOne, { Ticker } from 'tween-one';
9import { toArrayChildren, findChildInChildrenByKey, windowIsUndefined, mergeChildren, transformArguments } from './utils';
10import AnimTypes from './animTypes';
11
12var noop = function noop() {};
13
14export default /*#__PURE__*/forwardRef(function (props, ref) {
15 var _props$component = props.component,
16 component = _props$component === void 0 ? 'div' : _props$component,
17 _props$componentProps = props.componentProps,
18 componentProps = _props$componentProps === void 0 ? {} : _props$componentProps,
19 _props$interval = props.interval,
20 interval = _props$interval === void 0 ? 100 : _props$interval,
21 _props$duration = props.duration,
22 duration = _props$duration === void 0 ? 450 : _props$duration,
23 _props$delay = props.delay,
24 delay = _props$delay === void 0 ? 0 : _props$delay,
25 _props$type = props.type,
26 type = _props$type === void 0 ? 'right' : _props$type,
27 _props$animConfig = props.animConfig,
28 animConfig = _props$animConfig === void 0 ? null : _props$animConfig,
29 _props$ease = props.ease,
30 ease = _props$ease === void 0 ? 'easeOutQuart' : _props$ease,
31 _props$leaveReverse = props.leaveReverse,
32 leaveReverse = _props$leaveReverse === void 0 ? false : _props$leaveReverse,
33 _props$forcedReplay = props.forcedReplay,
34 forcedReplay = _props$forcedReplay === void 0 ? false : _props$forcedReplay,
35 _props$animatingClass = props.animatingClassName,
36 animatingClassName = _props$animatingClass === void 0 ? ['queue-anim-entering', 'queue-anim-leaving'] : _props$animatingClass,
37 _props$onEnd = props.onEnd,
38 onEnd = _props$onEnd === void 0 ? noop : _props$onEnd,
39 _props$appear = props.appear,
40 appear = _props$appear === void 0 ? true : _props$appear,
41 tagProps = _objectWithoutProperties(props, _excluded);
42 /**
43 * @param childrenShow;
44 * 记录 animation 里是否需要 startAnim;
45 * 当前元素是否处在显示状态
46 * enterBegin 到 leaveComplete 之前都处于显示状态
47 */
48
49
50 var childrenShow = useRef({});
51 /**
52 * @param keysToEnter;
53 * 记录进场的 key;
54 */
55
56 var keysToEnter = useRef([]);
57 var recordKeysToEnter = useRef([]);
58 /**
59 * @param keysToLeave;
60 * 记录出场的 key;
61 */
62
63 var keysToLeave = useRef([]);
64 var recordKeysToLeave = useRef([]);
65 /**
66 * @param placeholderTimeoutIds;
67 * 进场时 deley 的 timeout 记录;
68 */
69
70 var placeholderTimeoutIds = useRef({});
71 /**
72 * @param childRefs;
73 * 储存 children 的 ref;
74 */
75
76 var childRefs = useRef({});
77 /**
78 * @param recordAnimKeys;
79 * 记录启动动画 key
80 */
81
82 var recordAnimKeys = useRef({});
83 /**
84 * @param recordAnimKeys;
85 * 记录启动动画 key
86 */
87
88 var recordTweenKeys = useRef({});
89 /**
90 * @param oneEnterBool
91 * 记录第一次进入
92 */
93
94 var oneEnterBool = useRef(false);
95 var originalChildren = useRef([]);
96
97 var _useState = useState(),
98 _useState2 = _slicedToArray(_useState, 2),
99 child = _useState2[0],
100 setChild = _useState2[1];
101
102 var _useState3 = useState({}),
103 _useState4 = _slicedToArray(_useState3, 2),
104 childShow = _useState4[0],
105 setChildShow = _useState4[1];
106
107 var getTweenSingleConfig = function getTweenSingleConfig(data, num, enterOrLeave) {
108 var obj = {};
109 Object.keys(data).forEach(function (key) {
110 if (Array.isArray(data[key])) {
111 obj[key] = data[key][num];
112 } else if (!enterOrLeave && !num || enterOrLeave && num) {
113 obj[key] = data[key];
114 }
115 });
116 return obj;
117 };
118
119 var getTweenAnimConfig = function getTweenAnimConfig(data, num, enterOrLeave) {
120 if (Array.isArray(data)) {
121 return data.map(function (item) {
122 return getTweenSingleConfig(item, num, enterOrLeave);
123 });
124 }
125
126 return getTweenSingleConfig(data, num, enterOrLeave);
127 };
128
129 var getTweenType = function getTweenType($type, num) {
130 var data = AnimTypes[$type];
131 return getTweenAnimConfig(data, num);
132 };
133
134 var getAnimData = function getAnimData(key, i, enterOrLeave, startOrEnd) {
135 return (
136 /**
137 * transformArguments 第一个为 enter, 第二个为 leave;
138 * getTweenAnimConfig or getTweenType 第一个为到达的位置, 第二个为开始的位置。
139 * 用 tween-one 的数组来实现老的动画逻辑。。。
140 */
141 animConfig ? getTweenAnimConfig(transformArguments(animConfig, key, i)[enterOrLeave], startOrEnd, enterOrLeave) : getTweenType(transformArguments(type, key, i)[enterOrLeave], startOrEnd)
142 );
143 };
144
145 var getTweenData = function getTweenData(key, i, $type) {
146 var enterOrLeave = $type === 'enter' ? 0 : 1;
147 var start = $type === 'enter' ? 1 : 0;
148 var end = $type === 'enter' ? 0 : 1;
149 var animate = getAnimData(key, i, enterOrLeave, end);
150 var startAnim = $type === 'enter' && (forcedReplay || !childrenShow.current[key]) ? getAnimData(key, i, enterOrLeave, start) : null;
151 var $ease = transformArguments(ease, key, i)[enterOrLeave];
152 var $duration = transformArguments(duration, key, i)[enterOrLeave];
153
154 if (Array.isArray(ease) && (ease.length > 2 || Array.isArray(ease[0]))) {
155 $ease = $ease.map(function (num) {
156 return num * 100;
157 });
158 $ease = "M0,100C".concat($ease[0], ",").concat(100 - $ease[1], ",").concat($ease[2], ",").concat(100 - $ease[3], ",100,0");
159 }
160
161 return {
162 startAnim: startAnim,
163 animate: animate,
164 ease: $ease,
165 duration: $duration
166 };
167 };
168
169 var enterBegin = function enterBegin(key, e) {
170 var elem = e.targets;
171 elem.className = elem.className.replace(animatingClassName[1], '');
172
173 if (elem.className.indexOf(animatingClassName[0]) === -1) {
174 elem.className = "".concat(elem.className, " ").concat(animatingClassName[0]).trim();
175 }
176
177 if (keysToEnter.current.indexOf(key) >= 0) {
178 keysToEnter.current.splice(keysToEnter.current.indexOf(key), 1);
179 }
180
181 childrenShow.current[key] = true;
182 };
183
184 var enterComplete = function enterComplete(key, e) {
185 if (keysToLeave.current.indexOf(key) >= 0) {
186 return;
187 }
188
189 var elem = e.targets;
190 elem.className = elem.className.replace(animatingClassName[0], '').trim();
191 delete recordTweenKeys.current[key];
192 onEnd({
193 key: key,
194 type: 'enter',
195 target: elem
196 });
197 };
198
199 var leaveBegin = function leaveBegin(key, e) {
200 var elem = e.targets;
201 elem.className = elem.className.replace(animatingClassName[0], '');
202
203 if (elem.className.indexOf(animatingClassName[1]) === -1) {
204 elem.className = "".concat(elem.className, " ").concat(animatingClassName[1]).trim();
205 }
206 };
207
208 var leaveComplete = function leaveComplete(key, e) {
209 // 切换时同时触发 onComplete。 手动跳出。。。
210 toArrayChildren(props.children).findIndex(function (c) {
211 return c && c.key === key;
212 });
213
214 if (toArrayChildren(props.children).findIndex(function (c) {
215 return c && c.key === key;
216 }) >= 0) {
217 return;
218 }
219
220 delete childrenShow.current[key];
221 delete recordTweenKeys.current[key];
222 originalChildren.current = originalChildren.current.filter(function (c) {
223 return c.key !== key;
224 }); // 这里不用启动动画,,直接删;
225
226 if (keysToLeave.current.indexOf(key) >= 0) {
227 keysToLeave.current.splice(keysToLeave.current.indexOf(key), 1);
228 }
229
230 var needLeave = keysToLeave.current.some(function (c) {
231 return childShow[c];
232 });
233
234 if (!needLeave) {
235 var currentChildren = toArrayChildren(props.children);
236 setChild(currentChildren);
237 setChildShow(_objectSpread({}, childrenShow.current));
238 recordKeysToLeave.current.forEach(function (k) {
239 delete recordAnimKeys.current[k];
240 });
241 }
242
243 var elem = e.targets;
244 elem.className = elem.className.replace(animatingClassName[1], '').trim();
245 onEnd({
246 key: key,
247 type: 'leave',
248 target: elem
249 });
250 };
251
252 var performEnterBegin = function performEnterBegin(key) {
253 childShow[key] = true;
254 Ticker.clear(placeholderTimeoutIds.current[key]);
255 delete placeholderTimeoutIds.current[key];
256 setChildShow(_objectSpread({}, childShow));
257 };
258
259 var performEnter = function performEnter(key, i) {
260 var $interval = transformArguments(interval, key, i)[0];
261 var $delay = transformArguments(delay, key, i)[0];
262 placeholderTimeoutIds.current[key] = Ticker.timeout(function () {
263 performEnterBegin(key);
264 }, $interval * i + $delay);
265 };
266
267 var performLeave = function performLeave(key) {
268 Ticker.clear(placeholderTimeoutIds.current[key]);
269 delete placeholderTimeoutIds.current[key];
270 };
271
272 var getTweenOneEnterOrLeave = function getTweenOneEnterOrLeave(key, i, $delay, $type) {
273 var animateData = getTweenData(key, i, $type);
274
275 var onStart = function onStart(e) {
276 ($type === 'enter' ? enterBegin : leaveBegin)(key, e);
277 };
278
279 var onComplete = function onComplete(e) {
280 ($type === 'enter' ? enterComplete : leaveComplete)(key, e);
281 };
282
283 if (Array.isArray(animateData.animate)) {
284 var length = animateData.animate.length - 1;
285 var animation = animateData.animate.map(function (item, ii) {
286 return _objectSpread(_objectSpread({}, item), {}, {
287 startAt: animateData.startAnim ? animateData.startAnim[ii] : undefined,
288 duration: animateData.duration / length,
289 delay: !ii && $type === 'leave' ? $delay : 0,
290 onStart: !ii ? onStart : undefined,
291 onComplete: ii === length ? onComplete : undefined
292 });
293 });
294 return animation;
295 }
296
297 return _objectSpread(_objectSpread({}, animateData.animate), {}, {
298 startAt: animateData.startAnim || undefined,
299 ease: animateData.ease,
300 duration: animateData.duration,
301 onStart: onStart,
302 onComplete: onComplete,
303 delay: $delay
304 });
305 };
306
307 useEffect(function () {
308 return function () {
309 Object.keys(recordTweenKeys.current).forEach(function (key) {
310 var tween = recordTweenKeys.current[key];
311
312 if (!tween) {
313 return;
314 }
315
316 tween.kill();
317 });
318 };
319 }, []);
320 useEffect(function () {
321 var nextChildren = toArrayChildren(props.children).filter(function (c) {
322 return c;
323 });
324 var currentChildren = originalChildren.current.filter(function (item) {
325 return item;
326 });
327 var newChildren = mergeChildren(currentChildren, nextChildren);
328 var $keysToEnter = [];
329 var $keysToLeave = [];
330
331 if (!appear && !oneEnterBool.current) {
332 var $childShow = {};
333 newChildren.forEach(function (c) {
334 if (!c || !c.key) {
335 return;
336 }
337
338 $childShow[c.key] = true;
339 });
340 originalChildren.current = newChildren;
341 childrenShow.current = _objectSpread({}, $childShow);
342 setChildShow($childShow);
343 } else {
344 // console.log(nextChildren, recordAnimKeys.current, keysToEnter.current, keysToLeave.current);
345 currentChildren.forEach(function (c) {
346 if (!c) {
347 return;
348 }
349
350 var key = c.key;
351 var hasNext = findChildInChildrenByKey(nextChildren, key);
352
353 if (!hasNext && key) {
354 $keysToLeave.push(key);
355 Ticker.clear(placeholderTimeoutIds.current[key]);
356 delete placeholderTimeoutIds.current[key];
357 }
358 });
359 nextChildren.forEach(function (c) {
360 if (!c) {
361 return;
362 }
363
364 var key = c.key;
365 var hasPrev = findChildInChildrenByKey(currentChildren, key); // 如果 nextChildren 和当前的一致,且动画里是出场,改回进场;
366
367 if (!hasPrev && key || (!recordAnimKeys.current[key] || recordAnimKeys.current[key] === 'leave' || keysToEnter.current.indexOf(key) >= 0) && $keysToLeave.indexOf(key) === -1) {
368 $keysToEnter.push(key);
369 }
370 });
371 } // console.log('child update', $keysToEnter, $keysToLeave, newChildren);
372
373
374 keysToEnter.current = $keysToEnter; // keysToEnter 在启动时就会删除;
375
376 recordKeysToEnter.current = [].concat($keysToEnter);
377 keysToLeave.current = $keysToLeave;
378 recordKeysToLeave.current = [].concat($keysToLeave); // console.log($keysToEnter, $keysToLeave);
379
380 setChild(newChildren);
381 }, [props.children]);
382 useLayoutEffect(function () {
383 originalChildren.current = child || [];
384
385 if (appear || oneEnterBool.current) {
386 var $keysToEnter = _toConsumableArray(keysToEnter.current);
387
388 var $keysToLeave = _toConsumableArray(keysToLeave.current);
389
390 $keysToEnter.forEach(performEnter);
391 $keysToLeave.forEach(performLeave);
392 }
393
394 if (child) {
395 oneEnterBool.current = true;
396 }
397 }, [child]);
398 useLayoutEffect(function () {
399 if (child) {
400 child.forEach(function (item) {
401 var key = item.key;
402 var dom = childRefs.current[key];
403
404 if (!dom) {
405 return;
406 }
407
408 var animation;
409 var index = keysToLeave.current.indexOf(key); // children.findIndex(c => c.key === key);
410
411 var $interval = transformArguments(interval, key, index);
412 var $delay = transformArguments(delay, key, index); // 处理出场
413
414 if (index >= 0) {
415 if (recordAnimKeys.current[key] === 'leave') {
416 return;
417 }
418
419 var order = leaveReverse ? keysToLeave.current.length - index - 1 : index;
420 var d = $interval[1] * order + $delay[1];
421 animation = getTweenOneEnterOrLeave(key, index, d, 'leave');
422 recordAnimKeys.current[key] = 'leave';
423 } else {
424 if (recordAnimKeys.current[key] === 'enter' || keysToEnter.current.indexOf(key) === -1) {
425 return;
426 }
427
428 index = recordKeysToEnter.current.indexOf(key);
429
430 var _d = $interval[0] * index + $delay[0]; // console.log(recordAnimKeys.current[key], dom);
431
432
433 animation = getTweenOneEnterOrLeave(key, index, recordAnimKeys.current[key] === 'leave' ? _d : 0, 'enter');
434 recordAnimKeys.current[key] = 'enter';
435 }
436
437 if (recordTweenKeys.current[key]) {
438 recordTweenKeys.current[key].kill();
439 }
440
441 if (forcedReplay) {
442 var anim = _objectSpread(_objectSpread({}, Array.isArray(animation) ? animation[0].startAt : animation.startAt), {}, {
443 type: 'set'
444 });
445
446 TweenOne(dom, {
447 animation: anim
448 });
449 }
450
451 recordTweenKeys.current[key] = TweenOne(dom, {
452 animation: animation
453 });
454 });
455 }
456 }, [childShow, child]);
457 return useMemo(function () {
458 // console.log('--------render--------', childShow);
459 if (windowIsUndefined) {
460 return /*#__PURE__*/createElement(component, _objectSpread(_objectSpread(_objectSpread({}, tagProps), componentProps), {}, {
461 ref: ref
462 }));
463 }
464
465 var childrenToRender = toArrayChildren(child).map(function (item) {
466 if (!item || !item.key) {
467 return item;
468 }
469
470 return childShow[item.key] && /*#__PURE__*/cloneElement(item, {
471 ref: function ref(c) {
472 childRefs.current[item.key] = c instanceof Element ? c : findDOMNode(c);
473
474 if (!c) {
475 delete childRefs.current[item.key];
476 }
477 },
478 key: item.key
479 });
480 });
481
482 var p = _objectSpread(_objectSpread(_objectSpread({}, tagProps), componentProps), {}, {
483 ref: ref
484 });
485
486 return /*#__PURE__*/createElement(component, p, childrenToRender);
487 }, [childShow, child]);
488});
\No newline at end of file