Modal組件 長話不多說,接下來讓我們來動手實現一個react Modal組件。 我們先來看一下 "實際效果" Modal的佈局 首先,讓我們先思考下一個Modal組件的佈局是怎麼樣的。 我們先拿一個基本的Modal樣例來分析下。 如上圖所示,一個Modal組件可以分為mask、header、bo ...
Modal組件
長話不多說,接下來讓我們來動手實現一個react Modal組件。
我們先來看一下實際效果
Modal的佈局
首先,讓我們先思考下一個Modal組件的佈局是怎麼樣的。
我們先拿一個基本的Modal樣例來分析下。
如上圖所示,一個Modal組件可以分為mask、header、body和footer四部分,mask就不用說了,header主要是顯示title和關閉按鈕,body則是使用者自己傳的內容,footer主要是按鈕控制項。
Modal組件的參數(props)
我們確定了Modal組件的佈局之後,我們來思考一下Modal組件可支持傳遞的參數。
作為一個Modal組件,總要有標題(title)吧?要有用戶自定義傳入的內容(children),還有一個確定按鈕文案(okText)和一個取消按鈕文案(cancelText)吧,並且允許用戶傳入點擊確定按鈕的回調函數(onOk)和點擊取消按鈕的回調函數(onCancel)。也需要有一個控制Modal是否顯示的標誌吧(visible)。所以,大體上有以下7個變數。
Modal的樣式
首先,根據Modal組件的佈局和參數,我們可以確定react Modal的render函數如下:
我們都知道,Modal會覆蓋在其他元素上面,並且主要分為兩部分,一部分為mask陰影部分,一部分為主體內容,而且主體部分會覆蓋在陰影部分上面。讓我們一步步來實現這個效果。
實現mask效果
.modal-mask { // 讓mask鋪滿整屏 position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: black; opacity: 0.6; // 讓mask覆蓋在其他元素上面 z-index: 1000; }
實現主體內容的樣式,讓其覆蓋在其他元素(包括mask)上面,每一部分的作用可以看註釋
.modal-container { // 讓Modal的主體內容全局居中,通過position: fix以及top和left的50%讓主體內容的左上角居中,再通過transform:translate(-50%, -50%)來讓主體內容正確居中。 position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; min-width: 500px; border-radius: 4px; // 設置主體內容的z-index高於mask的,從而可以覆蓋mask z-index: 1001; }
接下來是body、footer和header樣式的實現,這個就直接貼代碼了。
.modal-title { padding: 30px; color: black; font-size: 20px; border-bottom: 1px solid #e8e8e8; } .modal-body { padding: 30px; font-size: 14px; border-bottom: 1px solid #e8e8e8; } .modal-footer { text-align: center; padding: 30px; display: flex; } .modal-footer .btn { flex: 1; height: 32px; text-align: center; } .modal-footer .modal-cancel-btn { background: white; margin-right: 30px; border-color: #d9d9d9; border-radius: 4px; } .modal-footer .modal-confirm-btn { background: #1890ff; color: white; }
Modal的交互邏輯實現
實際上Modal的交互是很簡單的,一般的調用方式如下:
由外部傳遞自定義的body內容以及一些自定義的屬性(比如title,點擊按鈕的回調還有Modal的標題)
我們先定義Modal組件里的props
設置一些預設的props,當用戶未傳入參數的時候,則使用預設的props
實現render函數,根據用戶傳入的參數以及預設參數來渲染Modal節點,如果用戶傳入的visible屬性為false(Modal不可見),則返回null,否則,返回Modal節點。
這樣,一個簡單的react Modal組件就完成了,上面的代碼可以在https://github.com/chenjigeng/empty 查看,並且可以直接看到一個demo例子。
效果圖如下:
最後再貼一下完整的Modal組件代碼
// Modal.tsx
import * as React from 'react';
import './Modal.css';
interface IModalProps {
children: React.ReactChild | React.ReactChildren | React.ReactElement<any>[],
title?: React.ReactChild,
visible: boolean,
onOk?: () => void,
onCancel?: () => void,
okText?: string,
cancelText?: string,
}
export default class Modal extends React.Component<IModalProps> {
public static defaultProps = {
cancelText: '取消',
okText: '確定',
visible: false,
}
public render() {
const { title, visible, okText, cancelText, children, onOk, onCancel } = this.props;
if (!visible) {
return null;
};
return (
<div>
<div className="modal-mask" onClick={onCancel}/>
<div className="modal-container">
<div className="modal-header">
<div className="modal-title">{title}</div>
</div>
<div className="modal-body">
{children}
</div>
<div className="modal-footer">
<button className="modal-cancel-btn btn" onClick={onCancel}>{cancelText}</button>
<button className="modal-confirm-btn btn" onClick={onOk}>{okText}</button>
</div>
</div>
</div>
)
}
}
// Moda.css
.modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: black;
opacity: 0.6;
z-index: 1000;
}
.modal-container {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
min-width: 500px;
border-radius: 4px;
z-index: 1001;
}
.modal-title {
padding: 30px;
color: black;
font-size: 20px;
border-bottom: 1px solid #e8e8e8;
}
.modal-body {
padding: 30px;
font-size: 14px;
border-bottom: 1px solid #e8e8e8;
}
.modal-footer {
text-align: center;
padding: 30px;
display: flex;
}
.modal-footer .btn {
flex: 1;
height: 32px;
text-align: center;
}
.modal-footer .modal-cancel-btn {
background: white;
margin-right: 30px;
border-color: #d9d9d9;
border-radius: 4px;
}
.modal-footer .modal-confirm-btn {
background: #1890ff;
color: white;
}