Refactor button click effect implementation

for better perfermance
This commit is contained in:
afc163 2018-08-08 16:01:07 +08:00
parent 45fb83d64c
commit b4d95f7e20
5 changed files with 53 additions and 35 deletions

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import { findDOMNode } from 'react-dom'; import { findDOMNode } from 'react-dom';
import * as PropTypes from 'prop-types'; import * as PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import clickAnimation from './clickAnimation';
import Icon from '../icon'; import Icon from '../icon';
import Group from './button-group'; import Group from './button-group';
@ -86,20 +87,22 @@ export default class Button extends React.Component<ButtonProps, any> {
block: PropTypes.bool, block: PropTypes.bool,
}; };
timeout: number;
delayTimeout: number; delayTimeout: number;
clickAnimation: {
cancel: () => void;
};
constructor(props: ButtonProps) { constructor(props: ButtonProps) {
super(props); super(props);
this.state = { this.state = {
loading: props.loading, loading: props.loading,
clicked: false,
hasTwoCNChar: false, hasTwoCNChar: false,
}; };
} }
componentDidMount() { componentDidMount() {
this.fixTwoCNChar(); this.fixTwoCNChar();
this.clickAnimation = clickAnimation(findDOMNode(this) as HTMLElement);
} }
componentWillReceiveProps(nextProps: ButtonProps) { componentWillReceiveProps(nextProps: ButtonProps) {
@ -122,12 +125,12 @@ export default class Button extends React.Component<ButtonProps, any> {
} }
componentWillUnmount() { componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
if (this.delayTimeout) { if (this.delayTimeout) {
clearTimeout(this.delayTimeout); clearTimeout(this.delayTimeout);
} }
if (this.clickAnimation) {
this.clickAnimation.cancel();
}
} }
fixTwoCNChar() { fixTwoCNChar() {
@ -148,12 +151,7 @@ export default class Button extends React.Component<ButtonProps, any> {
} }
handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => { handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
// Add click effect const { onClick } = this.props;
this.setState({ clicked: true });
clearTimeout(this.timeout);
this.timeout = window.setTimeout(() => this.setState({ clicked: false }), 500);
const onClick = this.props.onClick;
if (onClick) { if (onClick) {
(onClick as React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>)(e); (onClick as React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>)(e);
} }
@ -169,7 +167,7 @@ export default class Button extends React.Component<ButtonProps, any> {
type, shape, size, className, children, icon, prefixCls, ghost, loading: _loadingProp, block, ...rest type, shape, size, className, children, icon, prefixCls, ghost, loading: _loadingProp, block, ...rest
} = this.props; } = this.props;
const { loading, clicked, hasTwoCNChar } = this.state; const { loading, hasTwoCNChar } = this.state;
// large => lg // large => lg
// small => sm // small => sm
@ -190,7 +188,6 @@ export default class Button extends React.Component<ButtonProps, any> {
[`${prefixCls}-${sizeCls}`]: sizeCls, [`${prefixCls}-${sizeCls}`]: sizeCls,
[`${prefixCls}-icon-only`]: !children && icon, [`${prefixCls}-icon-only`]: !children && icon,
[`${prefixCls}-loading`]: loading, [`${prefixCls}-loading`]: loading,
[`${prefixCls}-clicked`]: clicked,
[`${prefixCls}-background-ghost`]: ghost, [`${prefixCls}-background-ghost`]: ghost,
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar, [`${prefixCls}-two-chinese-chars`]: hasTwoCNChar,
[`${prefixCls}-block`]: block, [`${prefixCls}-block`]: block,

View File

@ -0,0 +1,20 @@
import TransitionEvents from 'css-animation/lib/Event';
const clickAnimation = (node: HTMLElement) => {
function handler() {
node.removeAttribute('ant-click-animating');
node.setAttribute('ant-click-animating', 'true');
TransitionEvents.addEndEventListener(node, () => {
node.removeAttribute('ant-click-animating');
TransitionEvents.removeEndEventListener(node);
});
}
node.addEventListener('click', handler, false);
return {
cancel: () => {
node.removeEventListener('click', handler, false);
},
};
};
export default clickAnimation;

View File

@ -8,6 +8,7 @@
@btn-ghost-color: @text-color; @btn-ghost-color: @text-color;
@btn-ghost-bg: transparent; @btn-ghost-bg: transparent;
@btn-ghost-border: @border-color-base; @btn-ghost-border: @border-color-base;
@btn-animation-width: 6px;
// Button styles // Button styles
// ----------------------------- // -----------------------------
@ -131,21 +132,7 @@
margin-left: 8px; margin-left: 8px;
} }
&-clicked:after { &-danger[ant-click-animating]:after {
content: '';
position: absolute;
top: -1px;
left: -1px;
bottom: -1px;
right: -1px;
border-radius: inherit;
border: 0 solid @primary-color;
opacity: 0.4;
animation: buttonEffect .4s;
display: block;
}
&-danger&-clicked:after {
border-color: @btn-danger-color; border-color: @btn-danger-color;
} }
@ -180,11 +167,11 @@
@keyframes buttonEffect { @keyframes buttonEffect {
to { to {
opacity: 0; opacity: 0;
top: -6px; top: -@btn-animation-width;
left: -6px; left: -@btn-animation-width;
bottom: -6px; bottom: -@btn-animation-width;
right: -6px; right: -@btn-animation-width;
border-width: 6px; border-width: @btn-animation-width;
} }
} }
@ -197,3 +184,17 @@ a.@{btn-prefix-cls} {
line-height: @btn-height-sm - 2px; line-height: @btn-height-sm - 2px;
} }
} }
[ant-click-animating]:after {
content: '';
position: absolute;
top: -1px;
left: -1px;
bottom: -1px;
right: -1px;
border-radius: inherit;
border: 0 solid @primary-color;
opacity: 0.4;
animation: buttonEffect .4s cubic-bezier(.25, .8, .25, 1);
display: block;
}

View File

@ -3,7 +3,7 @@
exports[`Drawer render correctly 1`] = ` exports[`Drawer render correctly 1`] = `
<div> <div>
<button <button
class="ant-btn ant-btn-clicked" class="ant-btn"
type="button" type="button"
> >
<span> <span>

View File

@ -16,7 +16,7 @@ declare module 'shallowequal';
declare module 'warning'; declare module 'warning';
declare module 'css-animation'; declare module 'css-animation*';
declare module 'rc-select'; declare module 'rc-select';