我正在尝试创建一个按钮,以在发生某些事件(onclick,http成功/错误)时为标签添加动画。但是我无法弄清楚如何应用这些类并找到一种通过组件状态处理它的优雅方法。
单击按钮时,它会从IDLE
转换为BUSY
状态。承诺何时解决(SUCCESS
)或拒绝(FAILURE
)。 3秒后,它重置为IDLE
。
我正在尝试根据状态切换className。但是它不起作用,我不知道如何正确地做。我不确定是否应该(以及如何)使用react-transition-group
插件来顺利完成此操作,因为该组件没有条件地安装/卸载。
也许我应该使用CSS动画而不是CSS过渡。这会是更好的方法吗?
此处的实时示例:https://codesandbox.io/s/yjl5o5vr4v
这是我的代码:
SubmitButton.tsx
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { IconProp } from '@fortawesome/fontawesome-svg-core'
import classNames from 'classnames'
import './SubmitButton.css'
// flag to switch whether dummy request should succeed or fail
let workSuccess = true
interface IProps {}
interface IState {
status: 'IDLE' | 'BUSY' | 'SUCCESS' | 'FAILURE'
label: string
icon?: IconProp
}
const initialState: IState = {
status: 'IDLE',
label: 'Click',
icon: undefined,
}
class SubmitButton extends React.PureComponent<IProps, IState> {
public state: IState = { ...initialState }
public render() {
const { label, icon, status } = this.state
return (
<button className="SubmitButton" onClick={this.handleClick}>
<span
className={classNames({
'animation--after': status === 'BUSY',
'animation--before': status === 'SUCCESS' || status === 'FAILURE',
['animation']: status === 'IDLE',
})}
>
{icon && (
<FontAwesomeIcon className="SubmitButton__icon" icon={icon} />
)}
{label}
</span>
</button>
)
}
private handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
const { status } = this.state
if (status === 'IDLE') {
// animation: 'roll up' (out of view)
// animation: reset position
this.setState({
label: 'Loading...',
icon: 'spinner',
status: 'BUSY',
})
// animation: 'roll up' (into view)
try {
const response = await this.doWork()
// animation: 'roll up' (out of view)
if (response) {
// animation: reset position
this.setState({
label: 'OK',
icon: 'check',
status: 'SUCCESS',
})
// animation: 'roll up' (into view)
}
} catch (err) {
// animation: reset position
this.setState({
label: 'ERROR',
icon: 'exclamation',
status: 'FAILURE',
})
// animation: 'roll up' (into view)
} finally {
// animation: reset position
this.setState({ ...initialState })
// animation: 'roll up' (into view)
}
}
}
private doWork = () => {
return new Promise<boolean>((resolve: any, reject: any) => {
setTimeout(() => {
if (workSuccess) {
resolve(true)
} else {
reject('An error happened...')
}
workSuccess = !workSuccess
}, 3000)
})
}
}
export default SubmitButton
SubmitButton.css
.SubmitButton {
overflow: hidden;
cursor: pointer;
outline: none;
font-size: 16px;
padding: 12px 32px;
}
.SubmitButton__icon {
margin-right: 12px;
}
.animation {
display: inline-block;
transition: transform 300ms ease-out;
transform: translateY(0);
}
.animation--before {
transition: transform 300ms ease-out;
transform: translateY(50px);
}
.animation--after {
transition: transform 300ms ease-out;
transform: translateY(-50px);
}
答案 0 :(得分:0)
您可以使用gif图像代替FontAwesome图标。请检查以下代码。
目前,我以低质量的gif为例,但是您可以从项目中加载优质的gif。
class SubmitButton extends React.PureComponent<IProps, IState> {
public state: IState = { ...initialState };
public render() {
const { label, icon, status } = this.state;
return (
<>
<button className="SubmitButton" onClick={this.handleClick}>
<span
className={classNames({
"animation--after": status === "BUSY",
"animation--before": status === "SUCCESS" || status === "FAILURE",
["animation"]: status === "IDLE"
})}
>
{icon && (
<img src="http://www.ajaxload.info/cache/FF/FF/FF/00/00/00/1-0.gif" />
)}
{label}
</span>
</button>
</>
);
}