button作为最常见的页面元素,几乎所有的UI库都会将其封装为一个基础组件。

第一步:支持最基本的能力

在实际业务中,我们期望的是不用写css就能够得到一个满意样式的按钮,因此我们会将常用的几种应用场景提前封装好,使用时只需要传入对应的类型即可。

code.ts
1
<Button>default</Button>
2
<Button type="primary">primary</Button>
3
<Button type="warning">warning</Button>
4
<Button type="danger">danger</Button>

props中传入type,显示对应语义的样式。

code.ts
1
import React, { Component } from 'react';
2
import classnames from 'classnames';
3
import './style.scss';
4
5
class Button extends Component {
6
static defaultProps = {
7
loading: false,
8
type: 'default', // default warning primary
9
}
10
11
render() {
12
const { type, ghost, className, children, ...other } = this.props;
13
14
const cls = classnames('button', {
15
[`button-${type}`]: true,
16
'button-ghost': ghost
17
}, className);
18
return (
19
<button className={cls}>
20
{children}
21
</button>
22
)
23
}
24
}
25
26
export default Button;
code.ts
1
.button {
2
margin: 6px 4px;
3
cursor: pointer;
4
line-height: 1.6;
5
padding: 4px 15px;
6
border: 1px solid #d9d9d9;
7
border-radius: 4px;
8
color: #404040;
9
transition: 0.2s;
10
position: relative;
11
outline: none;
12
13
&::after {
14
border-width: 0;
15
}
16
17
i + span {
18
margin-left: 8px;
19
}
20
21
span + i {
22
margin-right: 8px;
23
}
24
25
&-primary {
26
background-color: #108ee9;
27
color: #FFF;
28
border: 1px solid #108ee9;
29
}
30
31
&-warning {
32
background-color:orange;
33
color: #fff;
34
border: 1px solid orange;
35
}
36
37
&-danger {
38
background-color: #f04134;
39
color: #fff;
40
border: 1px solid #f04134;
41
}
42
}

第二步,新增基础的交互元素

以default为例

新增hover样式

code.ts
1
&-default {
2
&:hover {
3
color: #108ee9;
4
border-color: #108ee9;
5
}
6
}

新增active样式

code.ts
1
&:active {
2
color: red;
3
border-color: red;
4
}

原则是hover的颜色比本色浅一点,active的颜色比本色深一点,这样会有比较好的视觉效果。

第三步:

点击效果。

code.ts
1
import React, { Component } from 'react';
2
import classnames from 'classnames';
3
import './style.scss';
4
5
class Button extends Component {
6
static defaultProps = {
7
type: 'default', // default warning primary
8
}
9
10
state = {
11
clicked: false
12
}
13
14
clickHandler = (e) => {
15
const { onClick } = this.props;
16
this.setState({
17
clicked: true
18
})
19
20
clearTimeout(this.timeout);
21
this.timeout = setTimeout(() => {
22
this.setState({ clicked: false })
23
}, 500);
24
25
onClick && onClick(e);
26
}
27
28
render() {
29
const { type, ghost, className, children, ...other } = this.props;
30
const { clicked } = this.state;
31
32
console.log(clicked);
33
34
const cls = classnames('button', {
35
[`button-${type}`]: true,
36
'button-ghost': ghost,
37
'button-clicked': clicked
38
}, className);
39
return (
40
<button
41
className={cls}
42
onClick={this.clickHandler}
43
{...other}
44
>
45
{children}
46
</button>
47
)
48
}
49
}
50
51
export default Button;
52
code.ts
1
&-clicked {
2
&:after {
3
display: block;
4
content: '';
5
position: absolute;
6
top: -1px;
7
left: -1px;
8
bottom: -1px;
9
right: -1px;
10
border-radius: inherit;
11
border: 0 solid #108ee9;
12
opacity: 0.4;
13
animation: buttonEffect .4s;
14
display: block;
15
}
16
}
code.ts
1
2
@keyframes buttonEffect {
3
to {
4
opacity: 0;
5
top: -6px;
6
left: -6px;
7
bottom: -6px;
8
right: -6px;
9
border-width: 6px;
10
}
11
}
12

思考:

如果让不同背景的颜色,点击之后的效果颜色与背景相同呢?

第四步:

集成了图标的按钮

code.ts
1
import React, { Component } from 'react';
2
import classnames from 'classnames';
3
import Icon from '../Icon';
4
import './style.scss';
5
6
class Button extends Component {
7
static defaultProps = {
8
type: 'default', // default warning primary
9
}
10
11
state = {
12
clicked: false
13
}
14
15
clickHandler = (e) => {
16
const { onClick } = this.props;
17
this.setState({
18
clicked: true
19
})
20
21
clearTimeout(this.timeout);
22
this.timeout = setTimeout(() => {
23
this.setState({ clicked: false })
24
}, 500);
25
26
onClick && onClick(e);
27
}
28
29
render() {
30
const { type, ghost, className, children, icon, ...other } = this.props;
31
const { clicked } = this.state;
32
33
console.log(clicked);
34
35
const cls = classnames('button', {
36
'button-clicked': clicked,
37
[`button-${type}`]: true,
38
'button-ghost': ghost,
39
}, className);
40
41
const iconNode = icon ? <Icon type={icon} /> : null;
42
return (
43
<button
44
className={cls}
45
onClick={this.clickHandler}
46
{...other}
47
>
48
{iconNode}
49
<span>{children}</span>
50
</button>
51
)
52
}
53
}
54
55
export default Button;
56

INFO
思考题:

现在我们需要当传入的icon为loading时,需要让图标能够选择起来,并且按钮处于disabled状态,并同时修改按钮样式为对应的disabled状态,应该如何实现呢?

专栏首页
到顶
专栏目录