React Modal 的一种粗暴实现
modal什么的很好做不就是个bool吗,要么显示要么隐藏。
一开始这个modal很简单,
const modal =(isShow)=><div style={{display:isShow?"block":"none"}}>Balbala</div>
但是这个样子的modal很突兀,很粗暴,连你自己也忍不住想加一个fade动画的吧。
在jquery里面那是相当好用,一个接口就搞定了。
fade-out;fade-in用css实现,很常规。
在react里面怎么实现呢。
本文来讲一讲对于modal 的一种粗暴的解决方案,带fadeIn fadeOut动画解决方案。
@-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fade-in {
-webkit-animation: fadeIn ease .3s forwards;
animation: fadeIn ease .3s forwards;
}
@-webkit-keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.fade-out {
-webkit-animation: fadeOut ease .3s forwards;
animation: fadeOut ease .3s forwards;
}
.modal.fade-out{
pointer-events: none;
}
在使用react的时候将你的modal放在父级组件的时候:
通过props提供接口访问。至少需要两个接口,一个bool变量用来控制是否显示,一个关闭的回调函数用来改变它的状态:
bool isVisible,void onClose()
除了通过接口的方法控制以外,还可以使用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({
})
}
这种写法也是很风骚,那么怎么实现呢。下次再说啊。