feat: before update animate

This commit is contained in:
hufeixiong
2022-01-27 16:34:07 +08:00
parent 5629f2755d
commit 8c079e20ba
14 changed files with 183 additions and 86 deletions

View File

@@ -1,3 +1,13 @@
## 0.11.11
修复动画导致旋转预览不生效。
新增容器overflow配置。
timeline部分样式调整。
example部分样式调整。
## 0.11.10 ## 0.11.10
新增对markline颜色样式设置 新增对markline颜色样式设置

View File

@@ -155,8 +155,5 @@ MIT
## Todo ## Todo
文档更新 重构动画
脚手架
基础组件库

View File

@@ -351,7 +351,6 @@ function AnimateControl(props: AnimateControlProps) {
} }
}); });
store.setData(cloneData); store.setData(cloneData);
props.config.timelineNeedleConfig.resetFunc();
}} }}
> >

View File

@@ -1,5 +1,5 @@
{ {
"version": "0.11.10", "version": "0.11.11",
"license": "MIT", "license": "MIT",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/dooringx-lib.esm.js", "module": "dist/dooringx-lib.esm.js",

View File

@@ -101,7 +101,7 @@ function Blocks(props: PropsWithChildren<BlockProps>) {
animationDelay: '', animationDelay: '',
animationDuration: '', animationDuration: '',
animationIterationCount: '', animationIterationCount: '',
animationFillMode: 'forwards', // animationFillMode: 'forwards',// 这个属性和transform冲突
animationTimingFunction: '', animationTimingFunction: '',
}; };
props.data.animate.forEach((v) => { props.data.animate.forEach((v) => {
@@ -129,12 +129,6 @@ function Blocks(props: PropsWithChildren<BlockProps>) {
return select; return select;
}, [props.data.animate]); }, [props.data.animate]);
const animationPlayState: CSSProperties = useMemo(() => {
return {
animationPlayState: props.data.animatePlayState || '',
};
}, [props.data.animatePlayState]);
const render = useMemo(() => { const render = useMemo(() => {
// 如果是编辑模式下,则需要包裹不能选中层,位移层,缩放控制层,平面移动层。 // 如果是编辑模式下,则需要包裹不能选中层,位移层,缩放控制层,平面移动层。
if (state && props.context === 'edit') { if (state && props.context === 'edit') {
@@ -170,7 +164,14 @@ function Blocks(props: PropsWithChildren<BlockProps>) {
> >
{/* 绝对定位元素 */} {/* 绝对定位元素 */}
{props.data.position !== 'static' && ( {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' && ( {props.data.position === 'static' && props.data.display !== 'inline' && (
@@ -180,7 +181,6 @@ function Blocks(props: PropsWithChildren<BlockProps>) {
width: '100%', width: '100%',
height: '100%', height: '100%',
...animateProps, ...animateProps,
...animationPlayState,
}} }}
> >
{state} {state}
@@ -188,7 +188,12 @@ function Blocks(props: PropsWithChildren<BlockProps>) {
)} )}
{/* 静态定位 行内 这里暂不考虑布局影响 */} {/* 静态定位 行内 这里暂不考虑布局影响 */}
{props.data.position === 'static' && props.data.display === 'inline' && ( {props.data.position === 'static' && props.data.display === 'inline' && (
<span style={{ pointerEvents: 'none', ...animateProps, ...animationPlayState }}> <span
style={{
pointerEvents: 'none',
...animateProps,
}}
>
{state} {state}
</span> </span>
)} )}
@@ -210,7 +215,6 @@ function Blocks(props: PropsWithChildren<BlockProps>) {
display: props.data.display, display: props.data.display,
transform: `rotate(${props.data.rotate.value}deg)`, transform: `rotate(${props.data.rotate.value}deg)`,
...animateProps, ...animateProps,
...animationPlayState,
}} }}
> >
{state} {state}
@@ -221,11 +225,10 @@ function Blocks(props: PropsWithChildren<BlockProps>) {
state, state,
props.context, props.context,
props.data, props.data,
props.iframe,
props.config, props.config,
props.iframe,
innerDragData, innerDragData,
animateProps, animateProps,
animationPlayState,
previewState.top, previewState.top,
previewState.left, previewState.left,
previewState.width, previewState.width,

View File

@@ -4,7 +4,7 @@ import { innerContainerDrag } from '../core/innerDrag';
import { NormalMarkLineRender } from '../core/markline'; import { NormalMarkLineRender } from '../core/markline';
import { IStoreData } from '../core/store/storetype'; import { IStoreData } from '../core/store/storetype';
import { wrapperMoveState } from './wrapperMove/event'; import { wrapperMoveState } from './wrapperMove/event';
import { CSSProperties, PropsWithChildren, useMemo } from 'react'; import { CSSProperties, PropsWithChildren, useMemo, useState } from 'react';
import Blocks from './blocks'; import Blocks from './blocks';
import { containerResizer } from '../core/resizeHandler/containerResizer'; import { containerResizer } from '../core/resizeHandler/containerResizer';
import React from 'react'; import React from 'react';
@@ -37,6 +37,10 @@ function Container(props: PropsWithChildren<ContainerProps>) {
return props.state.globalState.containerColor; return props.state.globalState.containerColor;
} }
}; };
const forceUpdate = useState(0)[1];
props.config.containerForceUpdate = () => {
forceUpdate((p) => p + 1);
};
return ( return (
<> <>
@@ -59,7 +63,7 @@ function Container(props: PropsWithChildren<ContainerProps>) {
width: `${props.state.container.width}px`, width: `${props.state.container.width}px`,
backgroundColor: bgColor(), backgroundColor: bgColor(),
position: 'relative', position: 'relative',
overflow: 'hidden', overflow: props.config.containerOverFlow ? 'hidden' : 'visible',
cursor: 'default', cursor: 'default',
...editContainerStyle, ...editContainerStyle,
}} }}

View File

@@ -45,7 +45,7 @@ function SettingsModal(props: SettingsModalPropsType) {
onCancel={() => props.onCancel()} onCancel={() => props.onCancel()}
onOk={() => { onOk={() => {
const res = form.getFieldsValue(); const res = form.getFieldsValue();
const { min, max, borderStyle } = res; const { min, max, borderStyle, containerOverFlow } = res;
if (max < min) { if (max < min) {
props.message.error(replaceLocale('error.minmax', zhCN['error.minmax'], props.config)); props.message.error(replaceLocale('error.minmax', zhCN['error.minmax'], props.config));
return; 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.borderColor = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`;
props.config.marklineConfig.borderStyle = borderStyle; props.config.marklineConfig.borderStyle = borderStyle;
props.config.containerOverFlow = containerOverFlow;
props.onOk(res); props.onOk(res);
props.config.containerForceUpdate();
return; return;
}} }}
> >
@@ -70,6 +72,7 @@ function SettingsModal(props: SettingsModalPropsType) {
max: props.config.scaleState.maxValue, max: props.config.scaleState.maxValue,
autofocus: props.config.timelineConfig.autoFocus, autofocus: props.config.timelineConfig.autoFocus,
borderStyle: props.config.marklineConfig.borderStyle, borderStyle: props.config.marklineConfig.borderStyle,
containerOverFlow: props.config.containerOverFlow,
}} }}
form={form} form={form}
> >
@@ -142,6 +145,19 @@ function SettingsModal(props: SettingsModalPropsType) {
<Radio value={false}>{replaceLocale('off', zhCN['off'], props.config)}</Radio> <Radio value={false}>{replaceLocale('off', zhCN['off'], props.config)}</Radio>
</Radio.Group> </Radio.Group>
</Form.Item> </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> </Form>
</Modal> </Modal>
); );

View File

@@ -40,9 +40,10 @@ export interface TimeLineConfigType {
scrollDom: null | HTMLDivElement; scrollDom: null | HTMLDivElement;
} }
export interface TimeLineNeedleConfigType { export interface TimeLineNeedleConfigType {
status: 'stop' | 'start'; status: 'stop' | 'start' | 'pause';
runFunc: Function; runFunc: Function;
resetFunc: Function; resetFunc: Function;
current: number;
} }
const animateTicker = new Array(iter).fill(1).map((_, y) => y); const animateTicker = new Array(iter).fill(1).map((_, y) => y);
@@ -164,9 +165,9 @@ const SortableList = SortableContainer(
let cacheBlock: IBlockType[] = []; let cacheBlock: IBlockType[] = [];
const needleWidth = 2; // const needleWidth = 2;
const initialLeft = 20 - needleWidth / 2; // const initialLeft = 20 - needleWidth / 2;
let timer: number | null = null; // let timer: number | null = null;
export function TimeLine(props: TimeLineProps) { export function TimeLine(props: TimeLineProps) {
const store = props.config.getStore(); const store = props.config.getStore();
const data = store.getData().block; const data = store.getData().block;
@@ -222,32 +223,71 @@ export function TimeLine(props: TimeLineProps) {
} }
}, [props.config]); }, [props.config]);
const [needle, setNeedle] = useState(initialLeft); // const [needle, setNeedle] = useState(initialLeft);
const needleStart = () => { //const needleStart = () => {
setNeedle(initialLeft); // props.config.timelineNeedleConfig.current = 0;
//每过0.1秒移动2 // setNeedle(initialLeft);
if (timer) { // //每过0.1秒移动2
window.clearInterval(timer); // if (timer) {
} // window.clearInterval(timer);
props.config.timelineNeedleConfig.status = 'start'; // }
timer = window.setInterval(() => { // props.config.timelineNeedleConfig.status = 'start';
if (needle < ruleWidth) { // const cloneData: IStoreData = deepcopy(store.getData());
setNeedle((pre) => pre + 2); // store.setData(cloneData);
} // store.cleanLast();
}, 100); // 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 = () => { // const needlePlay = async () => {
if (timer) { // if (timer) {
window.clearInterval(timer); // window.clearInterval(timer);
} // }
setNeedle(initialLeft); // await resetAnimate();
props.config.timelineNeedleConfig.status = 'stop'; // 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; // const needleReset = () => {
props.config.timelineNeedleConfig.runFunc = needleStart; // 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 ( return (
<div <div
@@ -280,44 +320,70 @@ export function TimeLine(props: TimeLineProps) {
minWidth: leftWidth, minWidth: leftWidth,
borderBottom: '1px solid #dadada', borderBottom: '1px solid #dadada',
height: itemHeight, height: itemHeight,
display: 'flex',
}} }}
> >
{replaceLocale('timeline.name', '组件名称', props.config)} {replaceLocale('timeline.name', '组件名称', props.config)}
<span <div
title="play"
style={{ style={{
display: 'inline-block', flex: 1,
marginLeft: '20px', textAlign: 'right',
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();
});
}
}} }}
> >
<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> </div>
{content} {content}
</div> </div>
@@ -330,7 +396,7 @@ export function TimeLine(props: TimeLineProps) {
position: 'relative', position: 'relative',
}} }}
> >
<div {/* <div
style={{ style={{
position: 'absolute', position: 'absolute',
transform: `translate(-${scrollx}px, 0px)`, transform: `translate(-${scrollx}px, 0px)`,
@@ -342,7 +408,7 @@ export function TimeLine(props: TimeLineProps) {
transition: 'left linear', transition: 'left linear',
willChange: 'left', willChange: 'left',
}} }}
></div> ></div> */}
<div <div
style={{ style={{
display: 'flex', display: 'flex',

View File

@@ -348,6 +348,8 @@ export class UserConfig {
public focusState = focusState; public focusState = focusState;
public collapsed = false; public collapsed = false;
public ticker = true; public ticker = true;
public containerOverFlow = true;
public containerForceUpdate = () => {};
public timeline = false; public timeline = false;
public timelineConfig: TimeLineConfigType = { public timelineConfig: TimeLineConfigType = {
autoFocus: true, autoFocus: true,
@@ -357,6 +359,7 @@ export class UserConfig {
status: 'stop', status: 'stop',
runFunc: () => {}, runFunc: () => {},
resetFunc: () => {}, resetFunc: () => {},
current: 0,
}; };
public waitAnimate = false; public waitAnimate = false;
public wrapperMoveState = wrapperMoveState; public wrapperMoveState = wrapperMoveState;

View File

@@ -43,6 +43,5 @@ export function createBlock(
value: 0, value: 0,
canRotate: true, canRotate: true,
}, },
animatePlayState: ComponentItem.initData.animatePlayState || '',
}; };
} }

View File

@@ -51,6 +51,5 @@ export interface IBlockType {
canRotate: boolean; canRotate: boolean;
}; };
animate: AnimateItem[]; animate: AnimateItem[];
animatePlayState: string;
fixed: boolean; // 用于制作fixed组件 fixed: boolean; // 用于制作fixed组件
} }

View File

@@ -46,7 +46,6 @@ function createDefaultModalBlock(): IStoreData['block'] {
value: 0, value: 0,
canRotate: false, canRotate: false,
}, },
animatePlayState: '',
}, },
]; ];
} }

View File

@@ -49,4 +49,5 @@ export const en: typeof zhCN = {
'error.minmax': 'The maximum value should be greater than or equal to the minimum value', 'error.minmax': 'The maximum value should be greater than or equal to the minimum value',
'settings.marklineColor': 'Markline color', 'settings.marklineColor': 'Markline color',
'settings.marklineStyle': 'Markline style', 'settings.marklineStyle': 'Markline style',
'settings.containerOverflow': 'Container Overflow',
}; };

View File

@@ -46,4 +46,5 @@ export const zhCN = {
'error.minmax': '最大值应大于等于最小值', 'error.minmax': '最大值应大于等于最小值',
'settings.marklineColor': '辅助线颜色', 'settings.marklineColor': '辅助线颜色',
'settings.marklineStyle': '辅助线样式', 'settings.marklineStyle': '辅助线样式',
'settings.containerOverflow': '容器边界外不显示元素',
}; };