手把手教你封裝一個(gè)Modal組件

環(huán)境搭建

create-react-app 快速搭建一個(gè) react 的開發(fā)環(huán)境,沒有用過的童鞋可參考官網(wǎng)

目錄

  1. 新建文件 src/modal/index.jsx, 并寫入一段簡單的測試代碼
import React, { Component } from 'react';
import './index.css';
class Modal extends Component {
  render() {
    return <div className="modal">
      這是一個(gè)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,出現(xiàn)如下結(jié)果,則表示環(huán)境搭建成功
modal_init.png

什么是 modal

  • 標(biāo)題區(qū)
  • 內(nèi)容區(qū)
  • 控制區(qū)
  • mask

modal 骨架實(shí)現(xiàn)

修改src/modal/index.jsx

import React from 'react';

export default class Modal extends React.Component {
    render() {
        return (
            <div>
                <div>
                    <div>標(biāo)題區(qū)</div>
                    <div>內(nèi)容區(qū)</div>
                    <div>
                        <button>取消</button>
                        <button>確定</button>
                    </div>
                </div>
                <div>mask</div>
            </div>
            )
    }
}

modal 樣式實(shí)現(xiàn)

修改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'>標(biāo)題區(qū)</div>
                    <div className='content'>內(nèi)容區(qū)</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_css.png

modal 功能開發(fā)

先思考一下 modal 組件需要實(shí)現(xiàn)哪些基本功能:

  • 可以通過 visible 控制 modal 的顯隱
  • 標(biāo)題區(qū) 和 內(nèi)容區(qū) 可以自定義顯示內(nèi)容
  • 點(diǎn)擊取消關(guān)閉 modal, 同時(shí)會調(diào)用名為 onClose 的回調(diào)
  • 點(diǎn)擊確認(rèn)會調(diào)用名為 onConfirm 的回調(diào),并關(guān)閉 modal
  • 點(diǎn)擊蒙層 mask 關(guān)閉 modal
  • animate 字段可以開啟/關(guān)閉動畫

控制 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'>標(biāo)題區(qū)</div>
                    <div className='content'>內(nèi)容區(qū)</div>
                    <div className='operator'>
                        <button className='close'>取消</button>
                        <button className='confirm'>確定</button>
                    </div>
                </div>
                <div className='mask'>mask</div>
            </div>
        )
    }
}

修改 src/App.js, 通過一個(gè) 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;

標(biāo)題區(qū)和內(nèi)容區(qū)可自定義

修改 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;

控制區(qū)功能及蒙層點(diǎn)擊功能

  • 要實(shí)現(xiàn)點(diǎn)擊取消按鈕關(guān)閉 modal, 那么就需要在 modal 中維護(hù)一個(gè)狀態(tài),然后用這個(gè)狀態(tài)來控制 modal 的顯隱,好像可行
  • 但是前面我們是通過父組件的 visible 控制 modal 的顯隱,似乎矛盾
  • 要結(jié)合起來,只通過 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
        }
    }
    
    // 首次渲染使用父組件的狀態(tài)更新 modal 中的 visible 狀態(tài),只調(diào)用一次
    componentDidMount() {
        this.setState({
            visible: this.props.visible
        })
    }

    // 每次接收 props 就根據(jù)父組件的狀態(tài)更新 modal 中的 visible 狀態(tài),首次渲染不會調(diào)用
    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;

小編是一名前端工程師,建了一個(gè)“前端內(nèi)推群”,里面有BAT等大廠的HR,也有知名獵頭,但大部分是前端工程師。群里會不定期發(fā)布前端相關(guān)的學(xué)習(xí)資源。群里的大佬們團(tuán)隊(duì)缺人,也會在群里招人。也聯(lián)合一些組織不定期會舉辦一些活動。逢年過節(jié)會有紅包。歡迎大家加入,一起成長,目前群人數(shù)較多,已達(dá)上限,可以先加機(jī)器人微信,注明“加群目的”,機(jī)器人會拉你入群。


機(jī)器人二維碼.jpeg
React技術(shù)交流群.jpeg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容