快速实现 React 业务弹窗组件

以前的需求有一些弹窗,弹窗内容比较复杂,在 React 项目中怎么方便高效地实现一个业务弹窗组件呢?经历了一段时间的演变,终于找到了比较方便的方法……bash

下面以简单的设置文案的弹窗为例列举一下弹窗的实现。antd

使用的基础弹窗组件是 antd modalapp

通常写法

比较常见的写法就是经过标签实现,也是我最开始经常使用的,但总以为不爽。ui

🎉 完整 demothis

弹窗组件的实现:spa

class DialogCustom extends React.Component {
 constructor(props) {
   super(props);
   this.state = { text: '' };
 }

 handleOk = () => {
   this.props.onOk(this.state.text);
   this.props.onClose();
 }

 onChange = (e) => {
   this.setState({ text: e.target.value });
 }

 render() {
   const { visible, onClose } = this.props;

   return (
     <Modal title="设置文案" visible={visible} onOk={this.handleOk} onCancel={onClose}>
       <Input value={this.state.text} onChange={this.onChange} />
     </Modal>
   );
 }
}
复制代码

使用组件:code

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      visible: false, // 要增长一个 visible 很麻烦有木有
      text: ''
    };
  }

  handleOk = (v) => {
    this.setState({ text: v });
  }

  showDialog = () => {
    this.setState({ visible: true });
  }

  handleClose = () => {
    this.setState({ visible: false });
  }

  render() { // 只能经过标签调用
    return (<div>
      <Button onClick={this.showDialog}>设置文案</Button>
      <DialogCustom visible={this.state.visible} onOk={this.handleOk} onClose={this.handleClose} />
      <div>{this.state.text}</div>
    </div>);
  }
}
复制代码

本方法的麻烦之处在于:component

  • 实现一个弹窗组件时每次都要引入 Modal 组件;cdn

  • 使用组件时,只能用标签的方式,且须要有一个 visible state 控制弹窗状态;blog

这样写一个其实也没什么,多了之后就烦了……

快捷调用

针对上面使用组件的麻烦,但愿使用组件时能够经过 xxx.show() 的方式快捷调用,不须要标签,不须要经过 visible state 控制。

解决:给组件加上 show 方法。跟上一方法的差异就是增长了一个 show 方法,另外 <Modal />visible 属性直接设为 true 便可

🎉 完整 demo

弹窗组件的实现:

class DialogCustom extends React.Component {
 static show = params => {
   let container = document.createElement("div");
   document.body.appendChild(container);

   function closeHandle() {
     ReactDOM.unmountComponentAtNode(container);
     document.body.removeChild(container);
     container = null;
   }

   ReactDOM.render(<DialogCustom {...params} onClose={closeHandle} />, container);
 };

 ...

 render() {
   return (<Modal  ... visible={true}>...</Modal>);
 }
}

复制代码

使用组件:

DialogCustom.show({ onOk: this.handleOk }); // 调用 show 想弹就弹,弹得响亮;直接可关闭,不用再增长 visible state 去控制
复制代码

本方法的麻烦之处在于:

  • 实现一个弹窗组件时每次都要引入 Modal,都要重写一次 show 方法

这样写几个,多了之后仍是烦了……

高阶组件

针对 “实现一个弹窗组件时每次都要引入 Modal,都要重写一次 show 方法” 的问题,能够用高阶组件解决

🎉 完整 demo

高阶组件:

const withDialog = WrappedComponent => {
 function EnhancedComponent(props) {
   const { title, onClose, ...others } = props;
   return (<Modal visible={true} title={title || WrappedComponent.title} footer={<div />}>
       <WrappedComponent {...others} onClose={onClose} />
   </Modal>);
 }

 EnhancedComponent.show = params => {
   let container = document.createElement("div");
   document.body.appendChild(container);

   function closeHandle() {
     ReactDOM.unmountComponentAtNode(container);
     document.body.removeChild(container);
     container = null;
   }

   ReactDOM.render(<EnhancedComponent {...params} onClose={closeHandle} />, container);
 };

 return EnhancedComponent;
};

复制代码

设置文案的组件几乎只要处理自己的逻辑,跟弹窗相关的有两个点:

  • 高阶组件赐予了业务组件一个 onClose 的属性以拥有关闭弹窗的权利,业务组件要注意下关闭弹窗的时机。
  • footer 就由业务组件全权承包了……

若是不须要弹窗了,那么不使用高阶组件,直接使用 SetText 便可(此处应该要再处理下 footer)。

业务组件:

@withDialog // 使用高阶组件,很关键
class SetText extends React.Component { // 只要处理自己的逻辑,几乎不用在乎弹窗
 static title = "设置文案";

 static defaultProps = {
   onClose: () => {}
 };

 constructor(props) {
   super(props);
   this.state = { text: "" };
 }

 onChange = e => {
   this.setState({ text: e.target.value });
 };

 handleOk = () => {
   this.props.onOk(this.state.text);
   this.props.onClose();
 };

 render() {
   return (<div>
     <Input value={this.state.text} onChange={this.onChange} />
     <div>
       <Button onClick={this.handleOk}>肯定</Button>
       <Button onClick={this.props.onClose}>取消</Button>
     </div>
   </div>);
 }
}
复制代码

使用组件:

SetText.show({ onOk: this.handleOk });
复制代码

本方法的问题在于:

  • footer 必定须要自定义,注意保持样式统一

经过这种方式,几乎不用侵入你的组件,你的组件就能够披上一个弹窗。

注:文本案例基于 antd modal 实现,但不限于 antd modal,你能够本身封装一个基础弹窗就能够实现弹弹弹。

相关文章
相关标签/搜索