讀zent源碼庫之Dialog組件完成

1、Dialog組件供應什麼功用,處理什麼題目?

zent的Dialog組件,運用姿態是如許的(代碼摘自zent官方文檔:https://www.youzanyun.com/zan…

import { Dialog, Button } from 'zent';

class Example extends React.Component {
  state = { visible: false }

  triggerDialog = visible => {
    this.setState({ visible });
  };

  render() {
    return (
      <div>
        <Button
          type="primary"
          onClick={() => this.triggerDialog(true)}
        >
          顯現
        </Button>
        <Dialog
                    visible={this.state.visible}
                    onClose={() => this.triggerDialog(false)}
                    title="對話框"
                >
                    <p>對話框內容</p>
                    <p>對話框其他內容</p>
                </Dialog>
      </div>
    );
  }
}

ReactDOM.render(<Example />, mountNode);
  1. 能夠經由過程visible屬性掌握彈層的顯現與隱蔽
  2. 能夠隨便的在Dialog組件里增加恣意多的內容
  3. 能夠在恣意位置運用Dialog組件

2、假如我來完成會怎樣做?

假如我來完成,實在很簡樸,用jQuery已寫了無數遍了,然則,想一想當初用jQuery來寫組件的時刻,異常輕易的能夠在body下面插進去一個div,而且綁定事宜,或許,直接把彈層的div寫到body標籤下面。

然則,react,倒是組件嵌套組件,一切組件都襯着在一個被稱為root的div下面,這可怎樣把一個節點掛載到body下面呢?

也簡樸,我直接用document.body.appendChild把組件直接插進去到body背面,然則發明,document.body.appendChild的參數必需是規範的dom節點,而react內里,經由過程this.props.children取出來的數據,並非規範的dom節點,這也好辦,把這些節點轉成規範的dom節點,然後插進去到body下面不就ok了?我是這麼想的。然則,末了一步,事宜怎樣綁定呢?這塊沒有深入研究了,不過我想,應當如許去完成也是沒有題目的。

趁便說一下,曾我還完成過一個React的彈層,然則必需放到最外層運用。。。哈哈,不說了,都是淚,侵入太強,沒法做到在恣意位置運用Dialog組件

3、zent的Dialog完成體式格局

zent完成體式格局,實在跟我上面說的基本思路是一致的,只是,用的要領不再是document.body.appendChild,而是用到了一個React供應的叫做ReactDOM.unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback)的要領,第一個參數是當前dialog地點的父組件,第二個參數是將要襯着的dialog內容,實在就是this.props.children,第三個參數是即將要掛載到body下面的一個div容器節點,callback就是勝利以後的回調了。

從函數名能夠看出,這個要領是不穩定的,然則,zent照樣用了,不過結果很好,哈哈。

zent的具體做法是,把ReactDOM.unstable_renderSubtreeIntoContainer要領放到了一個叫做Portal的組件上去完成這個功用,然後再把dialog內容放進這個Portal組件。

<PortalComponent
    visible={visible}
    onClose={this.onClose}
    className={`${prefix}-dialog-r-anchor`}
  >
    <DialogEl {...this.props} onClose={this.onClose} style={elStyle}>
      {this.props.children}
    </DialogEl>
</PortalComponent>

Portal組件本身的功用異常簡樸,僅僅只是擔任把其子組件襯着到body下面的一個新創建的div下面去。其他的邏輯(比方顯現、隱蔽、mask之類),全部都放到dialog組件本身上去完成。固然,顯現與隱蔽的功用,照樣由Portal來掌握,隱蔽的時刻,Portal會把當前的子組件從body上面卸載掉。

4、極簡完成

以下是一個極簡的Portal完成,即把本身的子組件襯着到body上面去。

import React from 'react';
import ReactDOM from 'react-dom';

export default class Portal extends React.Component {
  renderChildren() {
    const container = document.createElement('div');
    document.body.appendChild(container);
    ReactDOM.unstable_renderSubtreeIntoContainer(this, React.Children.only(this.props.children), container);
  }
  componentDidMount() {
    this.renderChildren();
  }
  render() {
    return null;
  }
}

以下是,基於Portal的Dialog組件的極簡完成:

import React from 'react';
import Portal from './portal';

export default class Dialog extends React.Component {
  render() {
    return <Portal>
      <div>{this.props.children}</div>
    </Portal>
  }
}

運用體式格局:

import React, { Component } from 'react';
import ReactDOM, { render } from 'react-dom';
import Dialog from './dialog';

class App extends Component {
  onTextClick = () => {
    console.log('clicked')
  }

  render() {
    return (
      <div>
        <Dialog >
          <div onClick={this.onTextClick}>this is dialog</div>
        </Dialog>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

固然,真正要完成一個Dialog須要斟酌的題目另有許多,比方掌握隱蔽與顯現、定製動畫,自定義款式,設置dialog的題目和其他屬性等等,只是這些我們在jQuery時期都已做過。

這裏重要剖析了Portal的完成,畢竟,在React內里,要把組件襯着到app根節點表面去並不輕易。

(全文完)

    原文作者:Happi
    原文地址: https://segmentfault.com/a/1190000015343992
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞