美文网首页前端攻城狮面试程序员
手把手教你封装一个Modal组件

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

作者: 孤烟漠儿 | 来源:发表于2018-09-27 19:10 被阅读3次

环境搭建

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

什么是 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_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 的显隐

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;

相关文章

网友评论

    本文标题:手把手教你封装一个Modal组件

    本文链接:https://www.haomeiwen.com/subject/wvkyoftx.html