手把手教你封裝一個Modal組件

環境搭建

create-react-app 快速搭建一個 react 的開發環境,沒有用過的童鞋可參考官網css

目錄

  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.cssreact

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

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_init.png

什麼是 modal

  • 標題區
  • 內容區
  • 控制區
  • mask

modal 骨架實現

修改src/modal/index.jsxgithub

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.jsxnpm

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.cssbash

.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;
}
複製代碼

效果如圖所示:app

modal_css.png

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 的顯隱ui

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;

複製代碼

React技術交流羣.jpeg
相關文章
相關標籤/搜索