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);
- 能夠經由過程visible屬性掌握彈層的顯現與隱蔽
- 能夠隨便的在Dialog組件里增加恣意多的內容
- 能夠在恣意位置運用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根節點表面去並不輕易。
(全文完)