feat: before update animate
This commit is contained in:
		| @@ -101,7 +101,7 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 			animationDelay: '', | ||||
| 			animationDuration: '', | ||||
| 			animationIterationCount: '', | ||||
| 			animationFillMode: 'forwards', | ||||
| 			//	animationFillMode: 'forwards',// 这个属性和transform冲突 | ||||
| 			animationTimingFunction: '', | ||||
| 		}; | ||||
| 		props.data.animate.forEach((v) => { | ||||
| @@ -129,12 +129,6 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 		return select; | ||||
| 	}, [props.data.animate]); | ||||
|  | ||||
| 	const animationPlayState: CSSProperties = useMemo(() => { | ||||
| 		return { | ||||
| 			animationPlayState: props.data.animatePlayState || '', | ||||
| 		}; | ||||
| 	}, [props.data.animatePlayState]); | ||||
|  | ||||
| 	const render = useMemo(() => { | ||||
| 		// 如果是编辑模式下,则需要包裹不能选中层,位移层,缩放控制层,平面移动层。 | ||||
| 		if (state && props.context === 'edit') { | ||||
| @@ -170,7 +164,14 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 				> | ||||
| 					{/* 绝对定位元素 */} | ||||
| 					{props.data.position !== 'static' && ( | ||||
| 						<div style={{ ...style, ...animateProps, ...animationPlayState }}>{state}</div> | ||||
| 						<div | ||||
| 							style={{ | ||||
| 								...style, | ||||
| 								...animateProps, | ||||
| 							}} | ||||
| 						> | ||||
| 							{state} | ||||
| 						</div> | ||||
| 					)} | ||||
| 					{/* 静态定位 非行内 这里暂不考虑布局影响 */} | ||||
| 					{props.data.position === 'static' && props.data.display !== 'inline' && ( | ||||
| @@ -180,7 +181,6 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 								width: '100%', | ||||
| 								height: '100%', | ||||
| 								...animateProps, | ||||
| 								...animationPlayState, | ||||
| 							}} | ||||
| 						> | ||||
| 							{state} | ||||
| @@ -188,7 +188,12 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 					)} | ||||
| 					{/* 静态定位 行内 这里暂不考虑布局影响 */} | ||||
| 					{props.data.position === 'static' && props.data.display === 'inline' && ( | ||||
| 						<span style={{ pointerEvents: 'none', ...animateProps, ...animationPlayState }}> | ||||
| 						<span | ||||
| 							style={{ | ||||
| 								pointerEvents: 'none', | ||||
| 								...animateProps, | ||||
| 							}} | ||||
| 						> | ||||
| 							{state} | ||||
| 						</span> | ||||
| 					)} | ||||
| @@ -210,7 +215,6 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 						display: props.data.display, | ||||
| 						transform: `rotate(${props.data.rotate.value}deg)`, | ||||
| 						...animateProps, | ||||
| 						...animationPlayState, | ||||
| 					}} | ||||
| 				> | ||||
| 					{state} | ||||
| @@ -221,11 +225,10 @@ function Blocks(props: PropsWithChildren<BlockProps>) { | ||||
| 		state, | ||||
| 		props.context, | ||||
| 		props.data, | ||||
| 		props.iframe, | ||||
| 		props.config, | ||||
| 		props.iframe, | ||||
| 		innerDragData, | ||||
| 		animateProps, | ||||
| 		animationPlayState, | ||||
| 		previewState.top, | ||||
| 		previewState.left, | ||||
| 		previewState.width, | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import { innerContainerDrag } from '../core/innerDrag'; | ||||
| import { NormalMarkLineRender } from '../core/markline'; | ||||
| import { IStoreData } from '../core/store/storetype'; | ||||
| import { wrapperMoveState } from './wrapperMove/event'; | ||||
| import { CSSProperties, PropsWithChildren, useMemo } from 'react'; | ||||
| import { CSSProperties, PropsWithChildren, useMemo, useState } from 'react'; | ||||
| import Blocks from './blocks'; | ||||
| import { containerResizer } from '../core/resizeHandler/containerResizer'; | ||||
| import React from 'react'; | ||||
| @@ -37,6 +37,10 @@ function Container(props: PropsWithChildren<ContainerProps>) { | ||||
| 			return props.state.globalState.containerColor; | ||||
| 		} | ||||
| 	}; | ||||
| 	const forceUpdate = useState(0)[1]; | ||||
| 	props.config.containerForceUpdate = () => { | ||||
| 		forceUpdate((p) => p + 1); | ||||
| 	}; | ||||
|  | ||||
| 	return ( | ||||
| 		<> | ||||
| @@ -59,7 +63,7 @@ function Container(props: PropsWithChildren<ContainerProps>) { | ||||
| 									width: `${props.state.container.width}px`, | ||||
| 									backgroundColor: bgColor(), | ||||
| 									position: 'relative', | ||||
| 									overflow: 'hidden', | ||||
| 									overflow: props.config.containerOverFlow ? 'hidden' : 'visible', | ||||
| 									cursor: 'default', | ||||
| 									...editContainerStyle, | ||||
| 								}} | ||||
|   | ||||
| @@ -45,7 +45,7 @@ function SettingsModal(props: SettingsModalPropsType) { | ||||
| 			onCancel={() => props.onCancel()} | ||||
| 			onOk={() => { | ||||
| 				const res = form.getFieldsValue(); | ||||
| 				const { min, max, borderStyle } = res; | ||||
| 				const { min, max, borderStyle, containerOverFlow } = res; | ||||
| 				if (max < min) { | ||||
| 					props.message.error(replaceLocale('error.minmax', zhCN['error.minmax'], props.config)); | ||||
| 					return; | ||||
| @@ -57,7 +57,9 @@ function SettingsModal(props: SettingsModalPropsType) { | ||||
| 				} | ||||
| 				props.config.marklineConfig.borderColor = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`; | ||||
| 				props.config.marklineConfig.borderStyle = borderStyle; | ||||
| 				props.config.containerOverFlow = containerOverFlow; | ||||
| 				props.onOk(res); | ||||
| 				props.config.containerForceUpdate(); | ||||
| 				return; | ||||
| 			}} | ||||
| 		> | ||||
| @@ -70,6 +72,7 @@ function SettingsModal(props: SettingsModalPropsType) { | ||||
| 					max: props.config.scaleState.maxValue, | ||||
| 					autofocus: props.config.timelineConfig.autoFocus, | ||||
| 					borderStyle: props.config.marklineConfig.borderStyle, | ||||
| 					containerOverFlow: props.config.containerOverFlow, | ||||
| 				}} | ||||
| 				form={form} | ||||
| 			> | ||||
| @@ -142,6 +145,19 @@ function SettingsModal(props: SettingsModalPropsType) { | ||||
| 						<Radio value={false}>{replaceLocale('off', zhCN['off'], props.config)}</Radio> | ||||
| 					</Radio.Group> | ||||
| 				</Form.Item> | ||||
| 				<Form.Item | ||||
| 					name="containerOverFlow" | ||||
| 					label={replaceLocale( | ||||
| 						'settings.containerOverflow', | ||||
| 						zhCN['settings.containerOverflow'], | ||||
| 						props.config | ||||
| 					)} | ||||
| 				> | ||||
| 					<Radio.Group> | ||||
| 						<Radio value={true}>{replaceLocale('on', zhCN['on'], props.config)}</Radio> | ||||
| 						<Radio value={false}>{replaceLocale('off', zhCN['off'], props.config)}</Radio> | ||||
| 					</Radio.Group> | ||||
| 				</Form.Item> | ||||
| 			</Form> | ||||
| 		</Modal> | ||||
| 	); | ||||
|   | ||||
| @@ -40,9 +40,10 @@ export interface TimeLineConfigType { | ||||
| 	scrollDom: null | HTMLDivElement; | ||||
| } | ||||
| export interface TimeLineNeedleConfigType { | ||||
| 	status: 'stop' | 'start'; | ||||
| 	status: 'stop' | 'start' | 'pause'; | ||||
| 	runFunc: Function; | ||||
| 	resetFunc: Function; | ||||
| 	current: number; | ||||
| } | ||||
|  | ||||
| const animateTicker = new Array(iter).fill(1).map((_, y) => y); | ||||
| @@ -164,9 +165,9 @@ const SortableList = SortableContainer( | ||||
|  | ||||
| let cacheBlock: IBlockType[] = []; | ||||
|  | ||||
| const needleWidth = 2; | ||||
| const initialLeft = 20 - needleWidth / 2; | ||||
| let timer: number | null = null; | ||||
| // const needleWidth = 2; | ||||
| // const initialLeft = 20 - needleWidth / 2; | ||||
| // let timer: number | null = null; | ||||
| export function TimeLine(props: TimeLineProps) { | ||||
| 	const store = props.config.getStore(); | ||||
| 	const data = store.getData().block; | ||||
| @@ -222,32 +223,71 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 		} | ||||
| 	}, [props.config]); | ||||
|  | ||||
| 	const [needle, setNeedle] = useState(initialLeft); | ||||
| 	// const [needle, setNeedle] = useState(initialLeft); | ||||
|  | ||||
| 	const needleStart = () => { | ||||
| 		setNeedle(initialLeft); | ||||
| 		//每过0.1秒移动2 | ||||
| 		if (timer) { | ||||
| 			window.clearInterval(timer); | ||||
| 		} | ||||
| 		props.config.timelineNeedleConfig.status = 'start'; | ||||
| 		timer = window.setInterval(() => { | ||||
| 			if (needle < ruleWidth) { | ||||
| 				setNeedle((pre) => pre + 2); | ||||
| 			} | ||||
| 		}, 100); | ||||
| 	}; | ||||
| 	//const needleStart = () => { | ||||
| 	// props.config.timelineNeedleConfig.current = 0; | ||||
| 	// setNeedle(initialLeft); | ||||
| 	// //每过0.1秒移动2 | ||||
| 	// if (timer) { | ||||
| 	// 	window.clearInterval(timer); | ||||
| 	// } | ||||
| 	// props.config.timelineNeedleConfig.status = 'start'; | ||||
| 	// const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 	// store.setData(cloneData); | ||||
| 	// store.cleanLast(); | ||||
| 	// timer = window.setInterval(() => { | ||||
| 	// 	if (needle < ruleWidth) { | ||||
| 	// 		setNeedle((pre) => { | ||||
| 	// 			props.config.timelineNeedleConfig.current = (pre - initialLeft) / 20; | ||||
| 	// 			console.log(props.config.timelineNeedleConfig.current); | ||||
| 	// 			return pre + 2; | ||||
| 	// 		}); | ||||
| 	// 	} | ||||
| 	// }, 100); | ||||
| 	//	}; | ||||
|  | ||||
| 	const needleReset = () => { | ||||
| 		if (timer) { | ||||
| 			window.clearInterval(timer); | ||||
| 		} | ||||
| 		setNeedle(initialLeft); | ||||
| 		props.config.timelineNeedleConfig.status = 'stop'; | ||||
| 	}; | ||||
| 	// const needlePlay = async () => { | ||||
| 	// 	if (timer) { | ||||
| 	// 		window.clearInterval(timer); | ||||
| 	// 	} | ||||
| 	// 	await resetAnimate(); | ||||
| 	// 	setTimeout(() => { | ||||
| 	// 		props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 	// 		timer = window.setInterval(() => { | ||||
| 	// 			if (needle < ruleWidth) { | ||||
| 	// 				setNeedle((pre) => { | ||||
| 	// 					props.config.timelineNeedleConfig.current = (pre - initialLeft) / 20; | ||||
| 	// 					return pre + 2; | ||||
| 	// 				}); | ||||
| 	// 			} | ||||
| 	// 		}, 100); | ||||
| 	// 	}); | ||||
| 	// }; | ||||
|  | ||||
| 	props.config.timelineNeedleConfig.resetFunc = needleReset; | ||||
| 	props.config.timelineNeedleConfig.runFunc = needleStart; | ||||
| 	// const needleReset = () => { | ||||
| 	// 	if (timer) { | ||||
| 	// 		window.clearInterval(timer); | ||||
| 	// 	} | ||||
| 	// 	props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 	// 	props.config.timelineNeedleConfig.current = 0; | ||||
| 	// 	resetAnimate(); | ||||
| 	// 	setNeedle(initialLeft); | ||||
| 	// 	store.cleanLast(); | ||||
| 	// }; | ||||
|  | ||||
| 	// const needlePause = () => { | ||||
| 	// 	props.config.timelineNeedleConfig.status = 'pause'; | ||||
| 	// 	if (timer) { | ||||
| 	// 		window.clearInterval(timer); | ||||
| 	// 	} | ||||
| 	// 	const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 	// 	store.setData(cloneData); | ||||
| 	// 	store.cleanLast(); | ||||
| 	// }; | ||||
|  | ||||
| 	// props.config.timelineNeedleConfig.resetFunc = needleReset; | ||||
| 	// props.config.timelineNeedleConfig.runFunc = needleStart; | ||||
|  | ||||
| 	return ( | ||||
| 		<div | ||||
| @@ -280,44 +320,70 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 								minWidth: leftWidth, | ||||
| 								borderBottom: '1px solid #dadada', | ||||
| 								height: itemHeight, | ||||
| 								display: 'flex', | ||||
| 							}} | ||||
| 						> | ||||
| 							{replaceLocale('timeline.name', '组件名称', props.config)} | ||||
| 							<span | ||||
| 								title="play" | ||||
| 							<div | ||||
| 								style={{ | ||||
| 									display: 'inline-block', | ||||
| 									marginLeft: '20px', | ||||
| 									cursor: 'pointer', | ||||
| 								}} | ||||
| 								onClick={() => { | ||||
| 									//缓存所有animate后执行 | ||||
| 									if (!WAIT) { | ||||
| 										WAIT = true; | ||||
| 										props.config.waitAnimate = true; | ||||
| 										const cache = data.map((v) => { | ||||
| 											return v.animate; | ||||
| 										}); | ||||
| 										const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 										cloneData.block.forEach((v) => { | ||||
| 											v.animate = []; | ||||
| 										}); | ||||
| 										store.setData(cloneData); | ||||
| 										setTimeout(() => { | ||||
| 											const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 											cloneData.block.forEach((v, i) => { | ||||
| 												v.animate = cache[i]; | ||||
| 											}); | ||||
| 											WAIT = false; | ||||
| 											props.config.waitAnimate = false; | ||||
| 											store.setData(cloneData); | ||||
| 											needleStart(); | ||||
| 										}); | ||||
| 									} | ||||
| 									flex: 1, | ||||
| 									textAlign: 'right', | ||||
| 								}} | ||||
| 							> | ||||
| 								<PlayCircleOutlined /> | ||||
| 							</span> | ||||
| 								{/* <span | ||||
| 									style={{ | ||||
| 										display: 'inline-block', | ||||
| 										cursor: 'pointer', | ||||
| 										marginRight: '10px', | ||||
| 									}} | ||||
| 								> | ||||
| 									<ReloadOutlined onClick={() => needleReset()} /> | ||||
| 								</span> | ||||
| 								<span | ||||
| 									style={{ | ||||
| 										display: 'inline-block', | ||||
| 										cursor: 'pointer', | ||||
| 										marginRight: '10px', | ||||
| 									}} | ||||
| 								> | ||||
| 									<PauseCircleOutlined onClick={() => needlePause()} /> | ||||
| 								</span> */} | ||||
| 								<span | ||||
| 									title="play" | ||||
| 									style={{ | ||||
| 										display: 'inline-block', | ||||
| 										marginRight: '20px', | ||||
| 										cursor: 'pointer', | ||||
| 									}} | ||||
| 									onClick={() => { | ||||
| 										//缓存所有animate后执行 | ||||
| 										if (!WAIT) { | ||||
| 											WAIT = true; | ||||
| 											props.config.waitAnimate = true; | ||||
| 											const cache = data.map((v) => { | ||||
| 												return v.animate; | ||||
| 											}); | ||||
| 											const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 											cloneData.block.forEach((v) => { | ||||
| 												v.animate = []; | ||||
| 											}); | ||||
| 											store.setData(cloneData); | ||||
| 											setTimeout(() => { | ||||
| 												const cloneData: IStoreData = deepcopy(store.getData()); | ||||
| 												cloneData.block.forEach((v, i) => { | ||||
| 													v.animate = cache[i]; | ||||
| 												}); | ||||
| 												WAIT = false; | ||||
| 												props.config.waitAnimate = false; | ||||
| 												store.setData(cloneData); | ||||
| 												store.cleanLast(); | ||||
| 											}); | ||||
| 										} | ||||
| 									}} | ||||
| 								> | ||||
| 									<PlayCircleOutlined /> | ||||
| 								</span> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 						{content} | ||||
| 					</div> | ||||
| @@ -330,7 +396,7 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 							position: 'relative', | ||||
| 						}} | ||||
| 					> | ||||
| 						<div | ||||
| 						{/* <div | ||||
| 							style={{ | ||||
| 								position: 'absolute', | ||||
| 								transform: `translate(-${scrollx}px, 0px)`, | ||||
| @@ -342,7 +408,7 @@ export function TimeLine(props: TimeLineProps) { | ||||
| 								transition: 'left linear', | ||||
| 								willChange: 'left', | ||||
| 							}} | ||||
| 						></div> | ||||
| 						></div> */} | ||||
| 						<div | ||||
| 							style={{ | ||||
| 								display: 'flex', | ||||
|   | ||||
| @@ -348,6 +348,8 @@ export class UserConfig { | ||||
| 	public focusState = focusState; | ||||
| 	public collapsed = false; | ||||
| 	public ticker = true; | ||||
| 	public containerOverFlow = true; | ||||
| 	public containerForceUpdate = () => {}; | ||||
| 	public timeline = false; | ||||
| 	public timelineConfig: TimeLineConfigType = { | ||||
| 		autoFocus: true, | ||||
| @@ -357,6 +359,7 @@ export class UserConfig { | ||||
| 		status: 'stop', | ||||
| 		runFunc: () => {}, | ||||
| 		resetFunc: () => {}, | ||||
| 		current: 0, | ||||
| 	}; | ||||
| 	public waitAnimate = false; | ||||
| 	public wrapperMoveState = wrapperMoveState; | ||||
|   | ||||
| @@ -43,6 +43,5 @@ export function createBlock( | ||||
| 			value: 0, | ||||
| 			canRotate: true, | ||||
| 		}, | ||||
| 		animatePlayState: ComponentItem.initData.animatePlayState || '', | ||||
| 	}; | ||||
| } | ||||
|   | ||||
| @@ -51,6 +51,5 @@ export interface IBlockType { | ||||
| 		canRotate: boolean; | ||||
| 	}; | ||||
| 	animate: AnimateItem[]; | ||||
| 	animatePlayState: string; | ||||
| 	fixed: boolean; // 用于制作fixed组件 | ||||
| } | ||||
|   | ||||
| @@ -46,7 +46,6 @@ function createDefaultModalBlock(): IStoreData['block'] { | ||||
| 				value: 0, | ||||
| 				canRotate: false, | ||||
| 			}, | ||||
| 			animatePlayState: '', | ||||
| 		}, | ||||
| 	]; | ||||
| } | ||||
|   | ||||
| @@ -49,4 +49,5 @@ export const en: typeof zhCN = { | ||||
| 	'error.minmax': 'The maximum value should be greater than or equal to the minimum value', | ||||
| 	'settings.marklineColor': 'Markline color', | ||||
| 	'settings.marklineStyle': 'Markline style', | ||||
| 	'settings.containerOverflow': 'Container Overflow', | ||||
| }; | ||||
|   | ||||
| @@ -46,4 +46,5 @@ export const zhCN = { | ||||
| 	'error.minmax': '最大值应大于等于最小值', | ||||
| 	'settings.marklineColor': '辅助线颜色', | ||||
| 	'settings.marklineStyle': '辅助线样式', | ||||
| 	'settings.containerOverflow': '容器边界外不显示元素', | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 hufeixiong
					hufeixiong