快速實現 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,你能夠本身封裝一個基礎彈窗就能夠實現彈彈彈。

相關文章
相關標籤/搜索