React封装组件(Button按钮和Modal模态框)

Button.tsx

import React, { Component } from "react"
import "./index.scss"
import classnames from "classnames"
type ButtonType = "default" | "primary" | "secondary" | "success" | "error"
type ButtonStyle = "outlined" | "container"
type ButtonSize = "small" | "normal" | "large"
type ButtonShape = "circle" | "square"

interface Props {
	type?: ButtonType
	variant?: ButtonStyle
	size?: ButtonSize
	children?: string
	disabled?: Boolean
	shape?: ButtonShape
	onClick?: () => void
}

export default class Button extends Component<Props> {
	static defaultProps = {
		type: "default",
		variant: "container",
		size: "normal",
		disabled: "false",
		shape: "square",
	}

	render() {
		const { type, onClick, variant, size, disabled, shape } = this.props
		const btnClassName = classnames({
			"button ": true,
			[`button-${type}-${variant}`]: true,
			[`button-${size}`]: true,
			[`button-disabled-${disabled}`]: true,
			[`button-${shape}`]: true,
		})
		return (
			<button className={btnClassName} onClick={onClick}>
				{this.props.children}
			</button>
		)
	}
}

Button.scss(注意引用顺序)

@import "btn-type.scss";

.button {
	line-height: 1.5715;
	margin: 0 5px;
	position: relative;
	display: flex;
	align-items: center;
	font-weight: 400;
	white-space: nowrap;
	text-align: center;
	// border: 1px solid transparent;
	cursor: pointer;
	transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
	
	padding: 6px 12px;
	font-size: 15px;
	border-radius: 10px;
}

@import "btn-size.scss";
@import "btn-disable.scss";
@import "btn-shape.scss";

btn-type.scss

/* 按钮默认样式 */
.button-default-outlined {
	color: #000000d9;
	border-color: #d9d9d9;
	background: #fff;
	&:hover{
		color: #40a9ff;
		border-color: #40a9ff;
	}
}
.button-default-container{
	color: #000000d9;
	border-color: #949292;
	background: #f0f0f0;
	&:hover{
		color: #40a9ff;
		border-color: #40a9ff;
	}
}

/* 按钮主样式 */
.button-primary-outlined {
	color: #40a9ff;
	border-color: #40a9ff;
	// background: #40a9ff;
	&:hover{
        color: #40a9ff;
		border-color: #0095ff;
		background: #edf7ff;
	}
}
.button-primary-container {
	color: #fff;
	border-color: #40a9ff;
	background: #40a9ff;
	&:hover{
		border-color: #69c0ff;
		background: #69c0ff;
	}
}

/* secondary样式 */
.button-secondary-container {
	color: #fff;
	border-color: #f36d2e;
	background: #ff8640f3;
	&:hover{
		color: #fff;
		border-color: #fd3300;
		background: #f36d2e;
	}
}
.button-secondary-outlined {
	color: #ff9456;
	border-color: #ff9456;
	// background: #ff8640f3;
	&:hover{
		color: #fa813b;
		border-color: #fd3300;
		background: #fff6eff3;
	}
}
.button-success-outlined {
	color: #2d9c00;
	border-color: #2d9c00;
	// background: #ff8640f3;
	&:hover{
		color: #237c00;
		border-color: #2d9b01d7;
		background: #ebfae5;
	}
}
.button-success-container {
	color: #fff;
	border-color: #2d9c00;
	background: #2d9c00;
	&:hover{
		color: #fff;
		border-color: #31ad00;
		background: #31ad00;
	}
}
.button-error-outlined {
	color: rgb(175, 0, 0);
	border-color: rgb(175, 0, 0);
	// background: #fff;
	&:hover{
		color: rgba(187, 0, 0, 0.76);
		border-color: #ff0000;
		background: rgb(252, 229, 229);
	}
}
.button-error-container {
	color: #fff;
	border-color: rgb(175, 0, 0);
	background: rgb(175, 0, 0);
	&:hover{
		color: #fff;
		border-color: rgb(223, 0, 0);
		background: rgb(158, 19, 19);
	}
}

btn-size.scss

.button{
    &-small{
        font-size: 14px;
        padding:1px 10px;    
    }
}
.button{
    &-large{
        font-size: 20px;
        padding:10px 20px;      
    }   
}

btn-shape.scss

.button-circle {
	padding: 0;
	min-width: 46px;
	min-height: 46px;
	font-size: 16px;
	display: flex;
	justify-content: center;
	align-items: center;
	overflow: hidden;
	border-radius: 50%;
	word-break: break-all;
}

btn-disabled.scss

.button-disabled-true{
    color:#47474783;
    border-color: #e5e5e5;
    background: #e5e5e5;
    cursor: not-allowed;
    &:hover{
        color:#47474783;
        border-color: #e5e5e5;
        background: #e5e5e5;
    }
}

Modal.scss

.modal {
	visibility: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	position: fixed;
	left: 0;
	top: 0;
	right: 0;
	bottom: 0;
}
.modal-mask {
	position: fixed;
	left: 0;
	top: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, 0.45);
	z-index: 100;
	transition: all 0.4s ease-in-out;
	opacity: 0;
}
.modal-box {
	box-sizing: border-box;
	position: relative;
	z-index: 101;
	width: 520px;
	background: #fff;
	border-radius: 5px;
	transition: all 0.3s ease-in-out;
	opacity: 0;
	transform: scale(0.7);
}
.modal-visible {
	visibility: visible;
}
.modal-visible .modal-mask {
	opacity: 1;
}
.modal-visible .modal-box {
	opacity: 1;
	transform: scale(1);
}
.modal-head {
	border-bottom: 1px solid #f0f0f0;
	padding: 16px 24px;
	display: flex;
	align-items: center;
	justify-content: space-between;
	color: #333;
	font-size: 16px;
	font-weight: 500;
}
.modal-close {
	cursor: pointer;
	opacity: 0.7;
}
.modal-close:hover {
	opacity: 1;
}
.modal-body {
	padding: 24px;
	font-size: 14px;
	color: #333;
	line-height: 1.6em;
}
.modal-footer {
	border-top: 1px solid #f0f0f0;
	padding: 10px 16px;
	display: flex;
	align-items: center;
	justify-content: flex-end;
}
.modal-footer > * {
	margin-left: 10px;
}

Modal.tsx

import React from "react"
import "./index.scss"
interface Props {
	visible: boolean
	title: string
	children: string
	footer: React.ReactNode
	onClose: () => void
}

export default class Modal extends React.Component<Props> {
	render() {
		let closeBtn = (
			<svg viewBox="64 64 896 896" focusable="false" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" className="modal-close" onClick={this.props.onClose}>
				<path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path>
			</svg>
		)

		return (
			<div className={this.props.visible ? "modal modal-visible" : "modal"}>
				<div className="modal-mask" onClick={this.props.onClose} />
				<div className="modal-box">
					<div className="modal-head">
						<span>{this.props.title}</span>
						{closeBtn}
					</div>
					<div className="modal-body">{this.props.children}</div>
					<div className="modal-footer">{this.props.footer}</div>
				</div>
			</div>
		)
	}
}

测试一下:

import React, { Component } from "react"
import Button from "../../components/Button"
import Modal from "../../components/Modal"
interface State {
	visible: boolean
}

export default class index extends Component {
	state: State = {
		visible: false,
	}

	showModal = () => {
		console.log(111111111)

		this.setState({
			visible: true,
		})
	}

	closeModal = () => {
		this.setState({
			visible: false,
		})
	}

	render() {
		return (
			<div style={{ display: "flex", alignItems: "center" }}>
				<Button>默认按钮</Button>
				<Button type="primary">主按钮</Button>
				<Button type="secondary" variant="container">
					次要按钮
				</Button>
				<Button type="success" variant="outlined">
					成功按钮
				</Button>
				<Button type="error">失败按钮</Button>
				<Button type="primary" disabled={true}>
					禁用按钮
				</Button>
				<Button type="primary" variant="container" onClick={this.showModal}>
					打开模态框
				</Button>
				<Button type="secondary" size="small">
					Small
				</Button>
				<Button type="success" size="normal">
					Normal
				</Button>
				<Button type="error" size="large">
					Large
				</Button>
				<Button type="primary" shape="circle">
					A
				</Button>

				<Modal
					visible={this.state.visible}
					title="蓝莓窗口"
					// 实现关闭窗口的逻辑
					onClose={this.closeModal}
					footer={[
						// 实现关闭窗口的逻辑
						<Button key="cancel" onClick={this.closeModal}>
							取消
						</Button>,
						// 实现关闭窗口的逻辑
						<Button key="ok" onClick={this.closeModal} type="primary">
							确认
						</Button>,
					]}
				>
					<p>Some contents...</p>
					<p>Some contents...</p>
					<p>Some contents...</p>
				</Modal>
			</div>
		)
	}
}

效果:

 

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值