乐趣区

关于javascript:react有关的一些事如何创建一个基于react的modal组件

看了一下,上一篇文章还是 1.1 号写的,一恍二十多天过来了。轻易写一点 react 无关的货色吧,这一篇文章次要参考了 https://www.cnblogs.com/demod…。
第一步:先写动态模版

src/component/Modal.tsx
import React from 'react';
import PropTypes from 'prop-types';
import './Modal.css'
interface ModalProps {onOk: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
    onCancel: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
    title: string;
    children: PropTypes.ReactElementLike;
}

export default class Modal extends React.Component<ModalProps> {render() {
        return (
            <div className="modal-container">
                <div className="modal-instance">
                    <div className="modal-title">
                        {this.props.title}
                    </div>

                    <div className="modal-content">
                        {this.props.children}
                    </div>

                    <div className="modal-footer">
                        <button onClick={this.props.onOk} className="button cancel-button"> 勾销 </button>
                        <button onClick={this.props.onCancel} className="submit submit-button"> 确认 </button>
                    </div>
                </div>
            </div>
        )
    }
} 

款式轻易写写:

.modal-container {
    position: fixed;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    background-color:rgba(4,4,4, 0.45);
}

.modal-instance {
    position: absolute;
    top: 50%;
    left: 50%;
    background-color: #ffffff;
    transform: translate(-50%, -50%);
    border-radius: 3px;
    border-style: 1px solid #353535;
}
.modal-title {
    height: 20px;
    width: 100%;
    min-width: 500px;
    font-size: 16px;
    font-weight: 500;
    display: flex;
    align-items: center;
}
.modal-content {padding: 5px;}
.modal-footer {
    height: 30px;
    font-size: 14px;
    display: flex;
    align-items: center;
}

当初开始调用 modal:

class Game extends React.Component<Props, TestState> {constructor(props: Props) {super(props);
    this.state = {isShowModal: false}
  }

  openModal = () => {
    this.setState({isShowModal: true})
  }
  render() {
    const ModalProps = {onOk: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {},
      onCancel:(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {},
      title: '测试 modal',
    }
    const {isShowModal} = this.state;
     return (<>
             {isShowModal && <Modal {...ModalProps}>
          <div>
            {'modal content'}
          </div>
        </Modal>}
        <button onClick={this.openModal}> 弹出 modal 框 </button>
      </>
    );

当初为止咱们实现了一个简略的动态的 modal 弹框。当初咱们心愿提供更多的调用形式,比方我心愿应用 ModalService.open(template, {onOk: () => {}, onCancel: () => {}}) 这种 api 进行调用。那咱们就须要进行封装:

export class ModalService {static open(props: ModalProps) {const modalContainer = document.createElement('div');
        document.body.appendChild(modalContainer);
        function onOk() {props.onOk();
            ReactDOM.unmountComponentAtNode(modalContainer);
        }

        function onCancel() {props.onCancel();
            ReactDOM.unmountComponentAtNode(modalContainer);
        }
        ReactDOM.render(<Modal {...props} onOk={onOk} onCancel={onCancel} />, modalContainer);
    }
}

当初咱们来测试一下 ModalService.open 的调用弹框形式

  openModalService = () => {const inputNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
      this.setState({inputName: event.target.value});
    }
    ModalService.open({onOk: () => {console.log(this.state.inputName);
        console.log('modal submit ???? by service, and close')
      },
      onCancel: () => {
        this.setState({inputName: ''})
        console.log('modal cancel ❌ by service, and close')
      },
      title: '这是 service 关上的',
      children: (<input type="text" value={this.state.inputName} onChange={inputNameChange} />)
    })
  }

这里其实有个 bug,这里的 input 弹框绑定了 value={this.state.inputName} 来绑定,然而其实这个 element 并没有真正的实现数据绑定,因为他只是创立了一次,并没有和 render 函数关联所以会呈现,任何对 input 文本框的输出,都看不到的状况。所以在有输出模版为 form 的状况下,更好的形式是应用组件调用,在 render 中应用组件调用的形式。

        {isShowModal && <Modal {...ModalProps}>
          <div>
            {'modal content'}
            <input type="text" value={this.state.inputNameStash} onChange={this.inputNameChange} />
          </div>
        </Modal>}

相似这样写。或者 modalservice.open 的形式关上一个 render 办法中定义的 ref。然而这样如同不太合乎 react 哲学(so?
最初封装一个链式调用的 api 吧。
1. 先革新 modalservice 使他返回一个 promise

export class ModalService {static open(props: ModalProps) {const modalContainer = document.createElement('div');
        document.body.appendChild(modalContainer);
                return new Promise<void>((resolve, reject) => {function onOk() {props.onOk && props.onOk();
                ReactDOM.unmountComponentAtNode(modalContainer);
                resolve();}

            function onCancel() {props.onCancel && props.onCancel();
                ReactDOM.unmountComponentAtNode(modalContainer);
                reject();}
            ReactDOM.render(<Modal {...props} onOk={onOk} onCancel={onCancel} />, modalContainer);
        })

    }
}

调用形式改为:

    openModalServicePromise = async () => {
        ModalService.open({
            title: '期待返回 promise 进行链式调用',
            children: '这是期待的 promise 返回的格局,这样更好用感觉'
        }).then(() => {console.log('modal 点击了确定✅, and close')
        }).catch(() => {console.log('modal 点击了勾销????️, and close')
        })
    }

几乎 perfect!

退出移动版