diff --git a/packages/amis-core/src/SchemaRenderer.tsx b/packages/amis-core/src/SchemaRenderer.tsx index f49750e02..0a746e9f2 100644 --- a/packages/amis-core/src/SchemaRenderer.tsx +++ b/packages/amis-core/src/SchemaRenderer.tsx @@ -119,12 +119,16 @@ export class SchemaRenderer extends React.Component { let id = props?.schema.id; id = formateId(id); if (animations.enter) { - this.animationTimeout.enter = (animations.enter.duration || 1) * 1000; + this.animationTimeout.enter = + ((animations.enter.duration || 1) + (animations.enter.delay || 0)) * + 1000; this.animationClassNames.enter = `${animations.enter.type}-${id}-enter`; this.animationClassNames.appear = this.animationClassNames.enter; } if (animations.exit) { - this.animationTimeout.exit = (animations.exit.duration || 1) * 1000; + this.animationTimeout.exit = + ((animations.exit.duration || 1) + (animations.exit.delay || 0)) * + 1000; this.animationClassNames.exit = `${animations.exit.type}-${id}-exit`; } } diff --git a/packages/amis-core/src/utils/animations.ts b/packages/amis-core/src/utils/animations.ts index a2b28838c..043d8f732 100644 --- a/packages/amis-core/src/utils/animations.ts +++ b/packages/amis-core/src/utils/animations.ts @@ -4,6 +4,7 @@ export interface AnimationsProps { enter?: { type: string; duration?: number; + delay?: number; }; attention?: { type: string; @@ -14,6 +15,7 @@ export interface AnimationsProps { exit?: { type: string; duration?: number; + delay?: number; }; } @@ -49,7 +51,12 @@ export function createAnimationStyle( if (enterAnimationConfig?.type) { enterStyle = generateStyleByAnimation( [`.${enterAnimationConfig.type}-${id}-enter`], - {name: enterAnimationConfig.type, duration: enterAnimationConfig.duration} + { + name: enterAnimationConfig.type, + duration: enterAnimationConfig.duration, + delay: enterAnimationConfig.delay, + fillMode: 'backwards' + } ); } @@ -75,6 +82,7 @@ export function createAnimationStyle( { name: exitAnimationConfig.type, duration: exitAnimationConfig.duration, + delay: exitAnimationConfig.delay, fillMode: 'forwards' } ); diff --git a/packages/amis-editor/src/tpl/style.tsx b/packages/amis-editor/src/tpl/style.tsx index 9a0f7e797..0e64fecef 100644 --- a/packages/amis-editor/src/tpl/style.tsx +++ b/packages/amis-editor/src/tpl/style.tsx @@ -1290,6 +1290,39 @@ setSchemaTpl( ); setSchemaTpl('animation', () => { + let timeoutId: any = null; + + function playAnimation(animations: any, id: string, type: string) { + let doc = document; + const isMobile = (window as any).editorStore.isMobile; + + if (isMobile) { + doc = (document.getElementsByClassName('ae-PreviewIFrame')[0] as any) + .contentDocument; + } + const el = doc.querySelector(`[name="${id}"]`); + id = formateId(id); + const className = `${animations[type].type}-${id}-${type}`; + el?.classList.add(className); + createAnimationStyle(id, animations); + + if (isMobile) { + let style = doc.getElementById('amis-styles'); + if (!style) { + style = doc.createElement('style'); + style.id = 'amis-styles'; + doc.head.appendChild(style); + } + style.innerHTML = styleManager.styleText; + } + if (timeoutId) { + clearTimeout(timeoutId); + } + + timeoutId = setTimeout(() => { + el?.classList.remove(className); + }, ((animations[type].duration || 1) + (animations[type].delay || 0)) * 1000 + 200); + } const animation = ( type: 'enter' | 'attention' | 'exit', label: string, @@ -1318,7 +1351,23 @@ setSchemaTpl('animation', () => { selectMode: 'group', options: animationOptions[type], label: '类型', - selectFirst: true + selectFirst: true, + onChange: (value: any, oldValue: any, obj: any, {data}: any) => { + const {animations, id} = data; + if (oldValue !== undefined) { + playAnimation( + { + ...animations, + [type]: { + ...animations[type], + type: value + } + }, + id, + type + ); + } + } }, { type: 'input-number', @@ -1327,7 +1376,47 @@ setSchemaTpl('animation', () => { value: 1, suffix: '秒', min: 0, - precision: 3 + precision: 3, + onChange: (value: any, oldValue: any, obj: any, {data}: any) => { + const {animations, id} = data; + if (oldValue !== undefined) { + playAnimation( + { + ...animations, + [type]: { + ...animations[type], + duration: value + } + }, + id, + type + ); + } + } + }, + { + label: '延迟', + type: 'input-number', + name: `animations.${type}.delay`, + value: 0, + suffix: '秒', + precision: 3, + onChange: (value: any, oldValue: any, obj: any, {data}: any) => { + const {animations, id} = data; + if (oldValue !== undefined) { + playAnimation( + { + ...animations, + [type]: { + ...animations[type], + delay: value + } + }, + id, + type + ); + } + } }, ...schema ] @@ -1341,33 +1430,8 @@ setSchemaTpl('animation', () => { size: 'sm', label: '播放', onClick: (e: any, {data}: any) => { - let doc = document; - const isMobile = (window as any).editorStore.isMobile; - - if (isMobile) { - doc = (document.getElementsByClassName('ae-PreviewIFrame')[0] as any) - .contentDocument; - } - let {id, animations} = data; - const el = doc.querySelector(`[name="${id}"]`); - id = formateId(id); - const className = `${animations[type].type}-${id}-${type}`; - el?.classList.add(className); - createAnimationStyle(id, animations); - - if (isMobile) { - let style = doc.getElementById('amis-styles'); - if (!style) { - style = doc.createElement('style'); - style.id = 'amis-styles'; - doc.head.appendChild(style); - } - style.innerHTML = styleManager.styleText; - } - - setTimeout(() => { - el?.classList.remove(className); - }, ((animations[type].duration || 1) + (animations[type].delay || 0)) * 1000); + const {animations, id} = data; + playAnimation(animations, id, type); } } ]; @@ -1389,14 +1453,6 @@ setSchemaTpl('animation', () => { })), {label: '无限', value: 'infinite'} ] - }, - { - label: '延迟', - type: 'input-number', - name: 'animations.attention.delay', - value: 0, - suffix: '秒', - precision: 3 } ]), ...animation('exit', '退出动画')