天天看點

React Modal 的一種粗暴實作

React Modal 的一種粗暴實作

modal什麼的很好做不就是個bool嗎,要麼顯示要麼隐藏。

一開始這個modal很簡單,

但是這個樣子的modal很突兀,很粗暴,連你自己也忍不住想加一個fade動畫的吧。

在jquery裡面那是相當好用,一個接口就搞定了。

fade-out;fade-in用css實作,很正常。

在react裡面怎麼實作呢。

本文來講一講對于modal 的一種粗暴的解決方案,帶fadeIn fadeOut動畫解決方案。

@-webkit-keyframes fadeIn {
  from {
    opacity: ;
  }
  to {
    opacity: ;
  }
}
@keyframes fadeIn {
  from {
    opacity: ;
  }
  to {
    opacity: ;
  }
}
.fade-in {
  -webkit-animation: fadeIn ease .s forwards;
          animation: fadeIn ease .s forwards;
}
@-webkit-keyframes fadeOut {
  from {
    opacity: ;
  }
  to {
    opacity: ;
  }
}
@keyframes fadeOut {
  from {
    opacity: ;
  }
  to {
    opacity: ;
  }
}
.fade-out {
  -webkit-animation: fadeOut ease .s forwards;
          animation: fadeOut ease .s forwards;
}
.modal.fade-out{
    pointer-events: none;
}
           

在使用react的時候将你的modal放在父級元件的時候:

  1. 通過props提供接口通路。至少需要兩個接口,一個bool變量用來控制是否顯示,一個關閉的回調函數用來改變它的狀态:

    bool isVisible,void onClose()

  2. 除了通過接口的方法控制以外,還可以使用ref。 在modal内部實作顯示隐藏的邏輯。然後ref到元件執行個體,至少需要兩個接口

    void show();void hide()

    ,然而這種方式實作起來的缺陷就是,每次使用的時候得先ref到元件的執行個體;這種寫法自身需要維護自己的顯示隐藏狀态。

在生命周期 componentWillMount時判斷初始狀态是否為顯示。如果初始狀态為不顯示,則延遲挂載,防止fadeIn動畫閃爍的副作用。

如果一開始modal就是不可見狀态的話,modal在挂載的時候會fadeOut一下,那麼你就會看見在視圖上你的彈窗突然一下消失。實際上,我們并不想讓它發生消失這件事。因為一開始的時候他是藏起來的就可以了。然而fadeoout這類的動畫它是把opacity從1變到0;

是以我們不得不需要一個狀态 hide 在一開始的時候将自己設定為hide,在props發生改變的時候對modal的顯示和隐藏狀态作出改變。并且至此以後再也不需要這個hide了。因為model已經進入了。

将真實render在componentWillReceiveProps中判斷好邏輯後再顯示出來。

class Modal extends Component {
    constructor(props){
        super(props);
        this.isFixed = false;
    }

    componentWillMount(){
        console.log(this.props);
        /*
         * 初始狀态為false的情況下,預設不可見;
         * 為防止fadeOut觸發,做以下操作。
         * */
        if( this.props.visible ){
            this.isFixed = true;
            this.render    = this.renderCurrent;
        }
    }

    componentWillReceiveProps(np){
        /*
        * magic
        */
        if( this.props.visible !== np.visible ){
            if( !this.isFixed ){
                this.render    = this.renderCurrent;
                this.isFixed = true;
            }
        }
    }

    renderCurrent(){
        const { visible,onClose } = this.props;
        return <div onClick={onClose}
                    className={visible ? "modal fade-in" : "modal fade-out"}>
            <div className="content">
                <div>BALABALABLA</div>
            </div>
        </div>
    }
    render(){
        return <div/>
    }
}
           

在元件的上下文通過成員變量isFixed 來判斷是不是已經完成了我們的modal fix行為。

因為js的靈活性,這樣實作起來是沒有問題的,對于性能來說,也沒有問題。

如果你要快速實作一個modal,并要求能夠有fadeIn,fadeOut 這種過度下過的話。

這個是來的最簡單的方式了。

在antd中,實作modal通過在React的RootNode createClass完成。

當第一次render的時候,如果你的modal是不顯示的話,它在Dom裡面其實就是個

當props發生有關isVisible的變化的時候,才真正的渲染了modal的dom結構。isVisible再次變化為false的時候,dom結構還是modal的dom結構,改變的隻是一個fade類名。

如果不使用第三方架構。強烈建議這種野路子的寫法。

當然,你還需要一個wrap層,弄成fixed的,然後你的modal窗體應該是absolute的,通過margin調整位置。給你的wrap在設定一個rgba的淺黑色背景,然後再在wrap上增加點選效果,使它可以點選遮罩關閉。

當然這個時候你又遇到了另一個新問題

因為事件傳遞,你又到modal的事件handle裡加上了preventDefault。

到此 基本上實作了一個可以用的modal 了。

另外的,給這個modal增加一些新的props,像增加一些諸如 title啊content啊 contentGetter啊這種東西,哇曬可以複用了。

當然,fadeout之外也可以使用slide,flip, scale,boom等。

那麼如何實作 在函數内部調用一個方法來顯示一個modal呢。

比如:

handleBtnClick(){
    modal.info("hello");
    modal.confirm({
        title:"dasd",
        content:"dasdas",
        onOk(){},
        onCancel(){}
    })
    modal.modal(reactElement)
    modal.warning({
    })
}
           

這種寫法也是很風騷,那麼怎麼實作呢。下次再說啊。