手把手教你封装一个Modal组件

环境搭建

create-react-app 快速搭建一个 react 的开发环境,没有用过的童鞋可参考官网

目录

  1. 新建文件 src/modal/index.jsx, 并写入一段简单的测试代码
import React, { Component } from 'react';
import './index.css';
class Modal extends Component {
  render() {
    return <div className="modal">
      这是一个modal组件
    </div>
  }
}
export default Modal;
复制代码
  1. 新建文件 src/modal/index.css

  2. 修改 src/App.js, 引入 Modal 组件

import React, { Component } from 'react';
import Modal from './modal';
import './App.css';

class App extends Component {
  render() {
    return (
      <Modal / >
    );
  }
}

export default App;
复制代码
  1. 在命令行输入npm start,出现如下结果,则表示环境搭建成功

什么是 modal

  • 标题区
  • 内容区
  • 控制区
  • mask

modal 骨架实现

修改src/modal/index.jsx

import React from 'react';

export default class Modal extends React.Component {
	render() {
		return (
			<div>
				<div>
					<div>标题区</div>
					<div>内容区</div>
					<div>
						<button>取消</button>
						<button>确定</button>
					</div>
				</div>
				<div>mask</div>
			</div>
			)
	}
}
复制代码

modal 样式实现

修改src/modal/index.jsx

import React from 'react';

export default class Modal extends React.Component {
	render() {
		return (
			<div className='wrapper'>
				<div className='modal'>
					<div className='title'>标题区</div>
					<div className='content'>内容区</div>
					<div className='operator'>
						<button className='close'>取消</button>
						<button className='confirm'>确定</button>
					</div>
				</div>
				<div className='mask'>mask</div>
			</div>
			)
	}
}
复制代码

修改 src/modal/index.css

.modal {
	width: 300px;
	height: 200px;
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
	margin: auto;
	z-index: 2000;
	background: #fff;
	border-radius: 2px;
	box-shadow:  inset 0 0 1px 0 #000;
}

.title {
	width: 100%;
	height: 50px;
	line-height: 50px;
	padding: 0 10px;
}

.content {
	width: 100%;
	height: 100px;
	padding: 0 10px;
}

.operator {
	width: 100%;
	height: 50px;

}

.close, .confirm {
	width: 50%;
	border: none;
	outline: none;
	color: #fff;
	background: #4CA791;
	cursor: pointer;
	
}
.close:active, .confirm:active {
	opacity: 0.6;
	transition: opacity 0.3s;
}

.mask {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background: #000;
	opacity: 0.6;
	z-index: 1000;
}
复制代码

效果如图所示:

modal 功能开发

先思考一下 modal 组件需要实现哪些基本功能:

  • 可以通过 visible 控制 modal 的显隐
  • 标题区 和 内容区 可以自定义显示内容
  • 点击取消关闭 modal, 同时会调用名为 onClose 的回调
  • 点击确认会调用名为 onConfirm 的回调,并关闭 modal
  • 点击蒙层 mask 关闭 modal
  • animate 字段可以开启/关闭动画

控制 modal 显隐

修改 src/modal/index.jsx

import React from 'react';

import './index.css';

export default class Modal extends React.Component {
	constructor(props) {
		super(props)
	}
	render() {
		// 通过父组件传递的 visible 控制显隐
		const { visible = true } = this.props
		return visible &&
		(
			<div className='wrapper'>
				<div className='modal'>
					<div className='title'>标题区</div>
					<div className='content'>内容区</div>
					<div className='operator'>
						<button className='close'>取消</button>
						<button className='confirm'>确定</button>
					</div>
				</div>
				<div className='mask'>mask</div>
			</div>
		)
	}
}
复制代码

修改 src/App.js, 通过一个 Button 来控制 modal 的显隐

import React, { Component, Fragment } from 'react';
import Modal from './modal';
import './App.css';


class App extends Component {
	constructor(props) {
		super(props)
		this.state = {
			visible: false,
		}
	}
	showModal = () => {
			this.setState({
				visible: true,
			});
	}
  render() {
  	const { visible } = this.state
    return (
    	<Fragment>
	    	<Modal visible={visible}/ >
	    	<button onClick={() => this.showModal()} style={{
	    		'background': '#4CA791',
	    		'color': '#fff',
	    		'border': 'none',
	    		'width': 300,
	    		'height': 50,
	    		'fontSize': 30,
	    	}}>切换显隐</button>
    	</Fragment>
      
    );
  }
}

export default App;

复制代码

标题区和内容区可自定义

修改 src/modal/index.jsx

import React from 'react';

import './index.css';

export default class Modal extends React.Component {
	constructor(props) {
		super(props)
	}
	render() {
		// 通过父组件传递的 visible 控制显隐
		const { visible = true, title, children } = this.props
		return visible &&
		(
			<div className='wrapper'>
				<div className='modal'>
					<div className='title'>{title}</div>
					<div className='content'>{children}</div>
					<div className='operator'>
						<button className='close'>取消</button>
						<button className='confirm'>确定</button>
					</div>
				</div>
				<div className='mask'>mask</div>
			</div>
		)
	}
}
复制代码

修改 src/App.js, 从外部传入自定义的 ‘title' 和 ‘content'

import React, { Component, Fragment } from 'react';
import Modal from './modal';
import './App.css';

class App extends Component {
	constructor(props) {
		super(props)
		this.state = {
			visible: false,
		}
	}
	showModal = () => {
			this.setState({
				visible: true,
			});
	}
  render() {
  	const { visible } = this.state
    return (
    	<Fragment>
	    	<Modal
	    	visible={visible}
	    	title='这是自定义的title'>
	    	这是自定义的content
	    	</Modal>
	    	<button onClick={() => this.showModal()} style={{
	    		'background': '#4CA791',
	    		'color': '#fff',
	    		'border': 'none',
	    		'width': 300,
	    		'height': 50,
	    		'fontSize': 30,
	    	}}>切换显隐</button>
    	</Fragment>
      
    );
  }
}

export default App;

复制代码

控制区功能及蒙层点击功能

  • 要实现点击取消按钮关闭 modal, 那么就需要在 modal 中维护一个状态,然后用这个状态来控制 modal 的显隐,好像可行
  • 但是前面我们是通过父组件的 visible 控制 modal 的显隐,似乎矛盾
  • 要结合起来,只通过 state 来控制 modal 的显隐,props 改变只会改变 state

修改 src/modal/index.jsx

import React from 'react';

import './index.css';

export default class Modal extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			visible: false
		}
	}
	
	// 首次渲染使用父组件的状态更新 modal 中的 visible 状态,只调用一次
	componentDidMount() {
		this.setState({
			visible: this.props.visible
		})
	}

	// 每次接收 props 就根据父组件的状态更新 modal 中的 visible 状态,首次渲染不会调用
	componentWillReceiveProps(props) {
		this.setState({
			visible: props.visible
		})
	}

	handleClose = () => {
		const { onClose } = this.props
		onClose && onClose()
		this.setState({
			visible: false
		})
	}
	handleConfirm = () => {
		const { onConfirm } = this.props
		onConfirm && onConfirm()
		this.setState({
			visible: false
		})
	}
	handleMask = () => {
		this.setState({
			visible: false
		})
	}
	render() {
		// 通过父组件传递的 visible 控制显隐
		const { title, children } = this.props

		const { visible = true } = this.state

		return visible &&
		(
			<div className='wrapper'>
				<div className='modal'>
					<div className='title'>{title}</div>
					<div className='content'>{children}</div>
					<div className='operator'>
						<button className='close' onClick={this.handleClose}>取消</button>
						<button className='confirm' onClick={this.handleConfirm}>确定</button>
					</div>
				</div>
				<div className='mask' onClick={this.handleMask}>mask</div>
			</div>
		)
	}
}
复制代码

修改 src/App.js, 从外部传入自定义的 onCloseonConfirm

import React, { Component, Fragment } from 'react';
import Modal from './modal';
import './App.css';



class App extends Component {
	constructor(props) {
		super(props)
		this.state = {
			visible: false,
		}
	}
	showModal = () => {
			this.setState({
				visible: true,
			});
	}
	onClose = () => {
		console.log('onClose');
	}
	onConfirm = () => {
		console.log('onConfirm');
	}
  render() {
  	const { visible } = this.state
    return (
    	<Fragment>
	    	<Modal
	    	visible={visible}
	    	title='这是自定义的title'
	    	onClose={this.onClose}
	    	onConfirm={this.onConfirm}
	    	>
	    	这是自定义的content
	    	</Modal>
	    	<button onClick={() => this.showModal()} style={{
	    		'background': '#4CA791',
	    		'color': '#fff',
	    		'border': 'none',
	    		'width': 300,
	    		'height': 50,
	    		'fontSize': 30,
	    	}}>切换显隐</button>
    	</Fragment>
      
    );
  }
}

export default App;

复制代码

转载于:https://juejin.im/post/5bb2e120e51d450e6548970a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值