mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: amis支持进入\强调\退出动画配置 (#11091)
* feat: amis支持进入\强调\退出动画配置 * chore: 增加样式管理器 * bugfix * 增加编辑器配置面板 * 动画增加播放功能 * 调整下文案 * bugfix * bugfix --------- Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>
This commit is contained in:
parent
7767ab7df0
commit
434a328619
@ -18,7 +18,13 @@ import {IScopedContext, ScopedContext} from './Scoped';
|
||||
import {Schema, SchemaNode} from './types';
|
||||
import {DebugWrapper} from './utils/debug';
|
||||
import getExprProperties from './utils/filter-schema';
|
||||
import {anyChanged, chainEvents, autobind, TestIdBuilder} from './utils/helper';
|
||||
import {
|
||||
anyChanged,
|
||||
chainEvents,
|
||||
autobind,
|
||||
TestIdBuilder,
|
||||
formateId
|
||||
} from './utils/helper';
|
||||
import {SimpleMap} from './utils/SimpleMap';
|
||||
import {bindEvent, dispatchEvent, RendererEvent} from './utils/renderer-event';
|
||||
import {isAlive} from 'mobx-state-tree';
|
||||
@ -28,6 +34,9 @@ import {buildStyle} from './utils/style';
|
||||
import {isExpression} from './utils/formula';
|
||||
import {StatusScopedProps} from './StatusScoped';
|
||||
import {evalExpression, filter} from './utils/tpl';
|
||||
import {CSSTransition} from 'react-transition-group';
|
||||
import {createAnimationStyle} from './utils/animations';
|
||||
import styleManager from './StyleManager';
|
||||
|
||||
interface SchemaRendererProps
|
||||
extends Partial<Omit<RendererProps, 'statusStore'>>,
|
||||
@ -89,17 +98,44 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
schema: any;
|
||||
path: string;
|
||||
|
||||
animationTimeout: {
|
||||
enter?: number;
|
||||
exit?: number;
|
||||
} = {};
|
||||
animationClassNames: {
|
||||
appear?: string;
|
||||
enter?: string;
|
||||
exit?: string;
|
||||
} = {};
|
||||
|
||||
reaction: any;
|
||||
unbindEvent: (() => void) | undefined = undefined;
|
||||
isStatic: any = undefined;
|
||||
|
||||
constructor(props: SchemaRendererProps) {
|
||||
super(props);
|
||||
const animations = props?.schema?.animations;
|
||||
if (animations) {
|
||||
let id = props?.schema.id;
|
||||
id = formateId(id);
|
||||
if (animations.enter) {
|
||||
this.animationTimeout.enter = (animations.enter.duration || 1) * 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.animationClassNames.exit = `${animations.exit.type}-${id}-exit`;
|
||||
}
|
||||
}
|
||||
|
||||
this.refFn = this.refFn.bind(this);
|
||||
this.renderChild = this.renderChild.bind(this);
|
||||
this.reRender = this.reRender.bind(this);
|
||||
this.resolveRenderer(this.props);
|
||||
this.dispatchEvent = this.dispatchEvent.bind(this);
|
||||
this.addAnimationAttention = this.addAnimationAttention.bind(this);
|
||||
this.removeAnimationAttention = this.removeAnimationAttention.bind(this);
|
||||
|
||||
// 监听statusStore更新
|
||||
this.reaction = reaction(
|
||||
@ -121,9 +157,18 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
if (this.props.schema.animations) {
|
||||
let {animations, id} = this.props.schema;
|
||||
id = formateId(id);
|
||||
createAnimationStyle(id, animations);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.reaction?.();
|
||||
this.unbindEvent?.();
|
||||
this.removeAnimationStyle();
|
||||
}
|
||||
|
||||
// 限制:只有 schema 除外的 props 变化,或者 schema 里面的某个成员值发生变化才更新。
|
||||
@ -154,6 +199,14 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeAnimationStyle() {
|
||||
if (this.props.schema.animations) {
|
||||
let {id} = this.props.schema;
|
||||
id = formateId(id);
|
||||
styleManager.removeStyles(id);
|
||||
}
|
||||
}
|
||||
|
||||
resolveRenderer(props: SchemaRendererProps, force = false): any {
|
||||
let schema = props.schema;
|
||||
let path = props.$path;
|
||||
@ -297,6 +350,25 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
addAnimationAttention(node: HTMLElement) {
|
||||
const {schema} = this.props || {};
|
||||
const {attention} = schema?.animations || {};
|
||||
if (attention) {
|
||||
let {id} = schema;
|
||||
id = formateId(id);
|
||||
node.classList.add(`${attention.type}-${id}-attention`);
|
||||
}
|
||||
}
|
||||
removeAnimationAttention(node: HTMLElement) {
|
||||
const {schema} = this.props || {};
|
||||
const {attention} = schema?.animations || {};
|
||||
if (attention) {
|
||||
let {id} = schema;
|
||||
id = formateId(id);
|
||||
node.classList.remove(`${attention.type}-${id}-attention`);
|
||||
}
|
||||
}
|
||||
|
||||
render(): JSX.Element | null {
|
||||
let {
|
||||
$path: _,
|
||||
@ -447,6 +519,8 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
} = schema;
|
||||
const Component = renderer.component!;
|
||||
|
||||
let animationIn = true;
|
||||
|
||||
// 原来表单项的 visible: false 和 hidden: true 表单项的值和验证是有效的
|
||||
// 而 visibleOn 和 hiddenOn 是无效的,
|
||||
// 这个本来就是个bug,但是已经被广泛使用了
|
||||
@ -458,7 +532,11 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
!renderer.isFormItem ||
|
||||
(schema.visible !== false && !schema.hidden))
|
||||
) {
|
||||
return null;
|
||||
if (schema.animations) {
|
||||
animationIn = false;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// withStore 里面会处理,而且会实时处理
|
||||
@ -526,12 +604,28 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
}
|
||||
}
|
||||
|
||||
const component = supportRef ? (
|
||||
let component = supportRef ? (
|
||||
<Component {...props} ref={this.childRef} />
|
||||
) : (
|
||||
<Component {...props} forwardedRef={this.childRef} />
|
||||
);
|
||||
|
||||
if (schema.animations) {
|
||||
component = (
|
||||
<CSSTransition
|
||||
in={animationIn}
|
||||
timeout={this.animationTimeout}
|
||||
classNames={this.animationClassNames}
|
||||
onEntered={this.addAnimationAttention}
|
||||
onExit={this.removeAnimationAttention}
|
||||
appear
|
||||
unmountOnExit
|
||||
>
|
||||
{component}
|
||||
</CSSTransition>
|
||||
);
|
||||
}
|
||||
|
||||
return this.props.env.enableAMISDebug ? (
|
||||
<DebugWrapper renderer={renderer}>{component}</DebugWrapper>
|
||||
) : (
|
||||
|
63
packages/amis-core/src/StyleManager.ts
Normal file
63
packages/amis-core/src/StyleManager.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import kebabCase from 'lodash/kebabCase';
|
||||
|
||||
interface Style {
|
||||
[id: string]: {
|
||||
[className: string]: {
|
||||
[propName: string]: string | number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class StyleManager {
|
||||
styles: Style;
|
||||
styleDom: HTMLStyleElement;
|
||||
styleText: string;
|
||||
|
||||
constructor() {
|
||||
this.styles = {};
|
||||
this.styleDom = document.createElement('style');
|
||||
this.styleDom.id = 'amis-styles';
|
||||
document.head.appendChild(this.styleDom);
|
||||
}
|
||||
|
||||
updateStyle(style: Style) {
|
||||
Object.keys(style).forEach(className => {
|
||||
if (!this.styles[className]) {
|
||||
this.styles[className] = style[className];
|
||||
} else {
|
||||
this.styles[className] = {
|
||||
...this.styles[className],
|
||||
...style[className]
|
||||
};
|
||||
}
|
||||
});
|
||||
this.updateStyleDom();
|
||||
}
|
||||
|
||||
removeStyles(id: string) {
|
||||
delete this.styles[id];
|
||||
this.updateStyleDom();
|
||||
}
|
||||
|
||||
updateStyleDom() {
|
||||
const styleText = Object.keys(this.styles)
|
||||
.map(id => {
|
||||
const style = this.styles[id];
|
||||
return Object.keys(style)
|
||||
.map(className => {
|
||||
return `${className} {${Object.keys(style[className])
|
||||
.map(propName => {
|
||||
return `${kebabCase(propName)}: ${style[className][propName]};`;
|
||||
})
|
||||
.join('')}}`;
|
||||
})
|
||||
.join('');
|
||||
})
|
||||
.join('');
|
||||
|
||||
this.styleDom.innerHTML = styleText;
|
||||
this.styleText = styleText;
|
||||
}
|
||||
}
|
||||
|
||||
export default new StyleManager();
|
@ -36,6 +36,7 @@ import './polyfills';
|
||||
import './renderers/builtin';
|
||||
import './renderers/register';
|
||||
export * from './utils/index';
|
||||
export * from './utils/animations';
|
||||
export * from './types';
|
||||
export * from './store';
|
||||
import * as utils from './utils/helper';
|
||||
@ -123,6 +124,8 @@ import type {IItem} from './store/list';
|
||||
import CustomStyle from './components/CustomStyle';
|
||||
import {StatusScoped} from './StatusScoped';
|
||||
|
||||
import styleManager from './StyleManager';
|
||||
|
||||
// @ts-ignore
|
||||
export const version = '__buildVersion';
|
||||
(window as any).amisVersionInfo = {
|
||||
@ -131,6 +134,7 @@ export const version = '__buildVersion';
|
||||
};
|
||||
|
||||
export {
|
||||
styleManager,
|
||||
clearStoresCache,
|
||||
updateEnv,
|
||||
Renderer,
|
||||
|
@ -3,6 +3,7 @@ import type {JSONSchema7} from 'json-schema';
|
||||
import {ListenerAction} from './actions/Action';
|
||||
import {debounceConfig, trackConfig} from './utils/renderer-event';
|
||||
import type {TestIdBuilder} from './utils/helper';
|
||||
import {AnimationsProps} from './utils/animations';
|
||||
|
||||
export interface Option {
|
||||
/**
|
||||
@ -307,6 +308,7 @@ export interface Schema {
|
||||
static?: boolean;
|
||||
children?: JSX.Element | ((props: any, schema?: any) => JSX.Element) | null;
|
||||
definitions?: Definitions;
|
||||
animations?: AnimationsProps;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
|
86
packages/amis-core/src/utils/animations.ts
Normal file
86
packages/amis-core/src/utils/animations.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import styleManager from '../StyleManager';
|
||||
|
||||
export interface AnimationsProps {
|
||||
enter?: {
|
||||
type: string;
|
||||
duration?: number;
|
||||
};
|
||||
attention?: {
|
||||
type: string;
|
||||
duration?: number;
|
||||
repeat?: string;
|
||||
delay?: number;
|
||||
};
|
||||
exit?: {
|
||||
type: string;
|
||||
duration?: number;
|
||||
};
|
||||
}
|
||||
|
||||
function generateStyleByAnimation(
|
||||
className: string[],
|
||||
animation: {
|
||||
name: string;
|
||||
duration?: number;
|
||||
iterationCount?: string;
|
||||
delay?: number;
|
||||
fillMode?: string;
|
||||
timingFunction?: string;
|
||||
}
|
||||
) {
|
||||
return {
|
||||
[className.join(',')]: {
|
||||
animationName: animation.name,
|
||||
animationDuration: `${animation.duration || 1}s`,
|
||||
animationIterationCount: animation.iterationCount || 1,
|
||||
animationDelay: `${animation.delay || 0}s`,
|
||||
animationTimingFunction: animation.timingFunction || 'ease',
|
||||
animationFillMode: animation.fillMode || 'none'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createAnimationStyle(
|
||||
id: string,
|
||||
animationsConfig: AnimationsProps
|
||||
) {
|
||||
const enterAnimationConfig = animationsConfig.enter;
|
||||
let enterStyle = {};
|
||||
if (enterAnimationConfig?.type) {
|
||||
enterStyle = generateStyleByAnimation(
|
||||
[`.${enterAnimationConfig.type}-${id}-enter`],
|
||||
{name: enterAnimationConfig.type, duration: enterAnimationConfig.duration}
|
||||
);
|
||||
}
|
||||
|
||||
const attentionAnimationConfig = animationsConfig.attention;
|
||||
let attentionStyle = {};
|
||||
if (attentionAnimationConfig?.type) {
|
||||
attentionStyle = generateStyleByAnimation(
|
||||
[`.${attentionAnimationConfig.type}-${id}-attention`],
|
||||
{
|
||||
name: attentionAnimationConfig.type,
|
||||
duration: attentionAnimationConfig.duration,
|
||||
iterationCount: attentionAnimationConfig.repeat || 'infinite',
|
||||
delay: attentionAnimationConfig.delay
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const exitAnimationConfig = animationsConfig.exit;
|
||||
let exitStyle = {};
|
||||
if (exitAnimationConfig?.type) {
|
||||
exitStyle = generateStyleByAnimation(
|
||||
[`.${exitAnimationConfig.type}-${id}-exit`],
|
||||
{
|
||||
name: exitAnimationConfig.type,
|
||||
duration: exitAnimationConfig.duration,
|
||||
fillMode: 'forwards'
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
styleManager.updateStyle({
|
||||
[id]: Object.assign({}, enterStyle, attentionStyle, exitStyle)
|
||||
});
|
||||
}
|
@ -2376,3 +2376,17 @@ export function supportsMjs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function formateId(id: string) {
|
||||
// 将className非法字符替换为短横线
|
||||
id = id.replace(/[^a-zA-Z0-9-]/g, '-');
|
||||
// 将连续的-替换为单个-
|
||||
id = id.replace(/-{2,}/g, '-');
|
||||
// 去掉首尾的-
|
||||
id = id.replace(/^-|-$/g, '');
|
||||
// 首字母不能为数字
|
||||
if (/^\d/.test(id)) {
|
||||
id = 'amis-' + id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
@ -790,7 +790,14 @@ export function filterSchemaForEditor(schema: any): any {
|
||||
Object.keys(schema).forEach(key => {
|
||||
const value = schema[key];
|
||||
if (
|
||||
~['visible', 'visibleOn', 'hidden', 'hiddenOn', 'toggled'].indexOf(key)
|
||||
~[
|
||||
'visible',
|
||||
'visibleOn',
|
||||
'hidden',
|
||||
'hiddenOn',
|
||||
'toggled',
|
||||
'animations' // 编辑态也不能有动画
|
||||
].indexOf(key)
|
||||
) {
|
||||
key = `$$${key}`;
|
||||
modified = true;
|
||||
|
@ -1,6 +1,448 @@
|
||||
import {setSchemaTpl, getSchemaTpl, defaultValue} from 'amis-editor-core';
|
||||
import type {SchemaCollection} from 'amis';
|
||||
import {createAnimationStyle, formateId, type SchemaCollection} from 'amis';
|
||||
import kebabCase from 'lodash/kebabCase';
|
||||
import {styleManager} from 'amis-core';
|
||||
|
||||
const animationOptions = {
|
||||
enter: [
|
||||
{
|
||||
label: '淡入',
|
||||
children: [
|
||||
{
|
||||
label: '淡入',
|
||||
value: 'fadeIn'
|
||||
},
|
||||
{
|
||||
value: 'fadeInDown',
|
||||
label: '从上淡入'
|
||||
},
|
||||
{
|
||||
value: 'fadeInDownBig',
|
||||
label: '从上淡入(加强效果)'
|
||||
},
|
||||
{
|
||||
value: 'fadeInLeft',
|
||||
label: '从左淡入'
|
||||
},
|
||||
{
|
||||
value: 'fadeInLeftBig',
|
||||
label: '从左淡入(加强效果)'
|
||||
},
|
||||
{
|
||||
value: 'fadeInRight',
|
||||
label: '从右淡入'
|
||||
},
|
||||
{
|
||||
value: 'fadeInRightBig',
|
||||
label: '从右淡入(加强效果)'
|
||||
},
|
||||
{
|
||||
value: 'fadeInUp',
|
||||
label: '从下淡入'
|
||||
},
|
||||
{
|
||||
value: 'fadeInUpBig',
|
||||
label: '从下淡入(加强效果)'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '回弹',
|
||||
children: [
|
||||
{
|
||||
value: 'backInDown',
|
||||
label: '从上回弹进入'
|
||||
},
|
||||
{
|
||||
value: 'backInLeft',
|
||||
label: '从左回弹进入'
|
||||
},
|
||||
{
|
||||
value: 'backInRight',
|
||||
label: '从右回弹进入'
|
||||
},
|
||||
{
|
||||
value: 'backInUp',
|
||||
label: '从下回弹进入'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '旋转',
|
||||
children: [
|
||||
{
|
||||
value: 'rotateIn',
|
||||
label: '旋转进入'
|
||||
},
|
||||
{
|
||||
value: 'rotateInDownLeft',
|
||||
label: '左上角旋转进入'
|
||||
},
|
||||
{
|
||||
value: 'rotateInDownRight',
|
||||
label: '右上角旋转进入'
|
||||
},
|
||||
{
|
||||
value: 'rotateInUpLeft',
|
||||
label: '左下角旋转进入'
|
||||
},
|
||||
{
|
||||
value: 'rotateInUpRight',
|
||||
label: '右下角旋转进入'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '滑动',
|
||||
children: [
|
||||
{
|
||||
value: 'slideInUp',
|
||||
label: '从下滑入'
|
||||
},
|
||||
{
|
||||
value: 'slideInDown',
|
||||
label: '从上滑入'
|
||||
},
|
||||
{
|
||||
value: 'slideInLeft',
|
||||
label: '从左滑入'
|
||||
},
|
||||
{
|
||||
value: 'slideInRight',
|
||||
label: '从右滑入'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '翻页',
|
||||
children: [
|
||||
{
|
||||
value: 'flip',
|
||||
label: '翻页'
|
||||
},
|
||||
{
|
||||
value: 'flipInY',
|
||||
label: '水平翻页'
|
||||
},
|
||||
{
|
||||
value: 'flipInX',
|
||||
label: '垂直翻页'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '弹跳',
|
||||
children: [
|
||||
{
|
||||
value: 'bounceIn',
|
||||
label: '弹跳进入'
|
||||
},
|
||||
{
|
||||
value: 'bounceInDown',
|
||||
label: '从上弹跳进入'
|
||||
},
|
||||
{
|
||||
value: 'bounceInLeft',
|
||||
label: '从左弹跳进入'
|
||||
},
|
||||
{
|
||||
value: 'bounceInRight',
|
||||
label: '从右弹跳进入'
|
||||
},
|
||||
{
|
||||
value: 'bounceInUp',
|
||||
label: '从下弹跳进入'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '缩放',
|
||||
children: [
|
||||
{
|
||||
value: 'zoomIn',
|
||||
label: '缩放进入'
|
||||
},
|
||||
{
|
||||
value: 'zoomInDown',
|
||||
label: '从上缩放进入'
|
||||
},
|
||||
{
|
||||
value: 'zoomInLeft',
|
||||
label: '从左缩放进入'
|
||||
},
|
||||
{
|
||||
value: 'zoomInRight',
|
||||
label: '从右缩放进入'
|
||||
},
|
||||
{
|
||||
value: 'zoomInUp',
|
||||
label: '从下缩放进入'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '其他',
|
||||
children: [
|
||||
{
|
||||
value: 'lightSpeedInLeft',
|
||||
label: '从左光速进入'
|
||||
},
|
||||
{
|
||||
value: 'lightSpeedInRight',
|
||||
label: '从右光速进入'
|
||||
},
|
||||
{
|
||||
value: 'rollIn',
|
||||
label: '滚动进入'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
attention: [
|
||||
{
|
||||
label: '弹跳',
|
||||
value: 'bounce'
|
||||
},
|
||||
{
|
||||
label: '闪烁',
|
||||
value: 'flash'
|
||||
},
|
||||
{
|
||||
value: 'headShake',
|
||||
label: '摇头'
|
||||
},
|
||||
{
|
||||
value: 'heartBeat',
|
||||
label: '心跳'
|
||||
},
|
||||
{
|
||||
value: 'jello',
|
||||
label: '果冻'
|
||||
},
|
||||
{
|
||||
label: '跳动',
|
||||
value: 'pulse'
|
||||
},
|
||||
{
|
||||
label: '摇摆',
|
||||
value: 'swing'
|
||||
},
|
||||
{
|
||||
label: '震动',
|
||||
value: 'tada'
|
||||
},
|
||||
{
|
||||
label: '晃动',
|
||||
value: 'wobble'
|
||||
},
|
||||
{
|
||||
label: '抖动',
|
||||
value: 'shake'
|
||||
},
|
||||
{
|
||||
value: 'shakeX',
|
||||
label: '水平抖动'
|
||||
},
|
||||
{
|
||||
value: 'shakeY',
|
||||
label: '垂直抖动'
|
||||
},
|
||||
{
|
||||
value: 'rubberBand',
|
||||
label: '橡皮筋'
|
||||
}
|
||||
],
|
||||
exit: [
|
||||
{
|
||||
label: '淡出',
|
||||
children: [
|
||||
{
|
||||
label: '淡出',
|
||||
value: 'fadeOut'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutDown',
|
||||
label: '向下淡出'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutDownBig',
|
||||
label: '向下淡出(加强效果)'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutLeft',
|
||||
label: '向左淡出'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutLeftBig',
|
||||
label: '向左淡出(加强效果)'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutRight',
|
||||
label: '向右淡出'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutRightBig',
|
||||
label: '向右淡出(加强效果)'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutUp',
|
||||
label: '向上淡出'
|
||||
},
|
||||
{
|
||||
value: 'fadeOutUpBig',
|
||||
label: '向上淡出(加强效果)'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '回弹',
|
||||
children: [
|
||||
{
|
||||
value: 'backOutDown',
|
||||
label: '向下回弹退出'
|
||||
},
|
||||
{
|
||||
value: 'backOutLeft',
|
||||
label: '向左回弹退出'
|
||||
},
|
||||
{
|
||||
value: 'backOutRight',
|
||||
label: '向右回弹退出'
|
||||
},
|
||||
{
|
||||
value: 'backOutUp',
|
||||
label: '向上回弹退出'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '旋转',
|
||||
children: [
|
||||
{
|
||||
value: 'rotateOut',
|
||||
label: '旋转退出'
|
||||
},
|
||||
{
|
||||
value: 'rotateOutDownLeft',
|
||||
label: '左上角旋转退出'
|
||||
},
|
||||
{
|
||||
value: 'rotateOutDownRight',
|
||||
label: '右上角旋转退出'
|
||||
},
|
||||
{
|
||||
value: 'rotateOutUpLeft',
|
||||
label: '左下角旋转退出'
|
||||
},
|
||||
{
|
||||
value: 'rotateOutUpRight',
|
||||
label: '右下角旋转退出'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '滑动',
|
||||
children: [
|
||||
{
|
||||
value: 'slideOutUp',
|
||||
label: '向上滑入'
|
||||
},
|
||||
{
|
||||
value: 'slideOutDown',
|
||||
label: '向下滑入'
|
||||
},
|
||||
{
|
||||
value: 'slideOutLeft',
|
||||
label: '向左滑入'
|
||||
},
|
||||
{
|
||||
value: 'slideOutRight',
|
||||
label: '向右滑入'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '翻页',
|
||||
children: [
|
||||
{
|
||||
value: 'flipOutY',
|
||||
label: '水平翻页'
|
||||
},
|
||||
{
|
||||
value: 'flipOutX',
|
||||
label: '垂直翻页'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '弹跳',
|
||||
children: [
|
||||
{
|
||||
value: 'bounceOut',
|
||||
label: '弹跳退出'
|
||||
},
|
||||
{
|
||||
value: 'bounceOutDown',
|
||||
label: '向下弹跳退出'
|
||||
},
|
||||
{
|
||||
value: 'bounceOutLeft',
|
||||
label: '向左弹跳退出'
|
||||
},
|
||||
{
|
||||
value: 'bounceOutRight',
|
||||
label: '向右弹跳退出'
|
||||
},
|
||||
{
|
||||
value: 'bounceOutUp',
|
||||
label: '向上弹跳退出'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '缩放',
|
||||
children: [
|
||||
{
|
||||
value: 'zoomOut',
|
||||
label: '缩放退出'
|
||||
},
|
||||
{
|
||||
value: 'zoomOutDown',
|
||||
label: '向上缩放退出'
|
||||
},
|
||||
{
|
||||
value: 'zoomOutLeft',
|
||||
label: '向左缩放退出'
|
||||
},
|
||||
{
|
||||
value: 'zoomOutRight',
|
||||
label: '向右缩放退出'
|
||||
},
|
||||
{
|
||||
value: 'zoomOutUp',
|
||||
label: '向下缩放退出'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '其他',
|
||||
children: [
|
||||
{
|
||||
value: 'lightSpeedOutLeft',
|
||||
label: '向左光速退出'
|
||||
},
|
||||
{
|
||||
value: 'lightSpeedOutRight',
|
||||
label: '向右光速退出'
|
||||
},
|
||||
{
|
||||
value: 'rollOut',
|
||||
label: '滚动退出'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
setSchemaTpl('style:formItem', ({renderer, schema}: any) => {
|
||||
return {
|
||||
@ -809,7 +1251,8 @@ setSchemaTpl(
|
||||
label: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
getSchemaTpl('animation')
|
||||
].filter(item => !~exclude.indexOf(item.key || ''));
|
||||
}
|
||||
);
|
||||
@ -845,3 +1288,118 @@ setSchemaTpl(
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
setSchemaTpl('animation', () => {
|
||||
const animation = (
|
||||
type: 'enter' | 'attention' | 'exit',
|
||||
label: string,
|
||||
schema: any = []
|
||||
) => [
|
||||
{
|
||||
type: 'switch',
|
||||
name: `animations.${type}`,
|
||||
pipeIn: (value: boolean) => !!value,
|
||||
pipeOut: (value: boolean) => {
|
||||
if (value) {
|
||||
return {};
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
label
|
||||
},
|
||||
{
|
||||
type: 'container',
|
||||
className: 'm-b ae-ExtendMore',
|
||||
visibleOn: `animations.${type}`,
|
||||
body: [
|
||||
{
|
||||
type: 'select',
|
||||
name: `animations.${type}.type`,
|
||||
selectMode: 'group',
|
||||
options: animationOptions[type],
|
||||
label: '类型',
|
||||
selectFirst: true
|
||||
},
|
||||
{
|
||||
type: 'input-number',
|
||||
name: `animations.${type}.duration`,
|
||||
label: '持续',
|
||||
value: 1,
|
||||
suffix: '秒',
|
||||
min: 0,
|
||||
precision: 3
|
||||
},
|
||||
...schema
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
visibleOn: `animations.${type}`,
|
||||
className: 'm-b',
|
||||
block: true,
|
||||
level: 'enhance',
|
||||
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);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
title: '动画',
|
||||
body: [
|
||||
...animation('enter', '进入动画'),
|
||||
...animation('attention', '强调动画', [
|
||||
{
|
||||
label: '重复',
|
||||
type: 'select',
|
||||
name: 'animations.attention.repeat',
|
||||
value: 'infinite',
|
||||
options: [
|
||||
...[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(i => ({
|
||||
label: i,
|
||||
value: i
|
||||
})),
|
||||
{label: '无限', value: 'infinite'}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '延迟',
|
||||
type: 'input-number',
|
||||
name: 'animations.attention.delay',
|
||||
value: 0,
|
||||
suffix: '秒',
|
||||
precision: 3
|
||||
}
|
||||
]),
|
||||
...animation('exit', '退出动画')
|
||||
]
|
||||
};
|
||||
});
|
||||
|
@ -38,6 +38,7 @@
|
||||
"@rc-component/mini-decimal": "^1.0.1",
|
||||
"amis-core": "^6.8.0",
|
||||
"amis-formula": "^6.8.0",
|
||||
"animate.css": "4.1.1",
|
||||
"classnames": "2.3.2",
|
||||
"codemirror": "^5.63.0",
|
||||
"downshift": "6.1.12",
|
||||
|
@ -7,5 +7,6 @@
|
||||
@import '../../../node_modules/video-react/dist/video-react';
|
||||
@import '../../../node_modules/cropperjs/dist/cropper';
|
||||
@import '../../../node_modules/office-viewer/dist/office';
|
||||
@import '../../../node_modules/animate.css/animate.min';
|
||||
|
||||
@import './components/react-datetime';
|
||||
|
Loading…
Reference in New Issue
Block a user