当前位置: 首页 > 科技观察

实现一个带有动态效果的React弹窗组件

时间:2023-03-16 15:56:08 科技观察

我们在写一些UI组件的时候,如果不考虑动态效果的话,实现起来很简单,主要就是在它们之间进行切换(类似Vue中的v-if属性)或者可见性切换(类似于Vue中的v-show属性)。1、在React中,没有动效的弹窗可以这样实现:interfaceModalProps{open:boolean;onClose?:()=>void;children?:any;}constModal=({open.onClose,children}:ModalProps)=>{if(!open){returnnull;}returncreatePortal(

{children}
x
,document.body);};用法:constApp=()=>{const[open,setOpen]=useState(false);return(setOpen(true)}>showmodalsetOpen(false)}>modalcontent
);};我们这里是用open属性来控制是否显示,但是完全没有渐变效果。如果我们要实现淡入淡出、缩放等动画效果,就需要修改这个。2、自己实现动态弹窗很多同学经常在显示的时候有动态效果,关闭的时候没有动态效果。动画的时间控制不好。这里我们先自己实现动效的流动。最初意识到的时候,动画只有开始状态和结束状态,需要大量的变量和逻辑来控制动画。后来参考了react-transition-group组件的实现,将动效拆分成几个部分,每个部分单独控制。开启动画效果顺序:enter->enter-active->enter-done;关闭动画效果顺序:exit->exit-active->exit-done;动画过程处于enter-active和exit-active的过程中。然后我们用一个变量active来控制是否关闭动画,参数open只控制是执行展开动画还是关闭动画。当open和active都为false时,弹窗将被销毁。constModal=({open,children,onClose})=>{const[active,setActive]=useState(false);//弹窗的存在周期if(!open&&!active){returnull;}returnReactDOM.createPortal({children}
x,document.body,);};这里继续在动画过程中添加变化:const[aniClassName,setAniClassName]=useState('');//动态类//transition完成监听函数constonTransitionEnd=()=>{//当open为rue时,结束状态为'enter-done'//当open不为false时,结束状态为'exit-done'setAniClassName(open?'enter-done':'exit-done');//如果open为false,当动画结束时,弹窗生命周期结束if(!open){setActive(false);}};useEffect(()=>{if(open){setActive(true);setAniClassName('enter');//setTimeout用于切换类,让transition动起来setTimeout(()=>{setAniClassName('enter-active');});}else{setAniClassName('exit');setTimeout(()=>{setAniClassName('exit-active');});}},[open]);Modal组件完整代码如下:constModal=({open,children,onClose})=>{const[active,setActive]=useState(false);//弹窗存在期const[aniClassName,setAniClassName]=useState('');//动态类constonTransitionEnd=()=>{setAniClassName(open?'enter-done':'exit-done');if(!open){setActive(false);}};useEffect(()=>{if(open){setActive(true);setAniClassName('enter');setTimeout(()=>{setAniClassName('enter-active');});}else{setAniClassName('exit');setTimeout(()=>{setAniClassName('退出-active');});}},[open]);if(!open&&!active){returnnull;}returnReactDOM.createPortal({children}x,document.body,);};动效的流水已经完成实现了,样式也要一起写比如我们要实现淡入淡出的效果:.enter{opacity:0;}.enter-active{transition:opacity200msease-in-out;opacity:1;}.enter-done{opacity:1;}.exit{opacity:1;}.exit-active{opacity:0;transition:opacity200msease-in-out;}.exit-done{opacity:0;}如果想实现放大缩小的zoom效果,只需要修改这些类。已实现具有动态效果的弹出窗口。用法:constApp=()=>{const[open,setOpen]=useState(false);return(setOpen(true)}>showmodalsetOpen(false)}>modalcontent);};类似的还有Toast之类的,也可以这样实现。3.react-transition-group在实现动效的思路上我们借鉴了react-transition-group中的CSSTransition组件。CSSTransition已经帮我封装了动效打开和关闭的过程。我们在实现弹窗的时候可以直接使用这个组件。这里有一个重要的属性:unmountOnExit,表示动画结束后卸载该组件。constModal=({open,onClose})=>{//http://reactcommunity.org/react-transition-group/css-transition///属性为true/false,true为展开动态效果,false是关闭DynamicreturncreatePortal({children}x,document.body,);};使用CSSTransition组件后,Modal的动态效果就方便多了。4.总结至此,实现了要动画的ReactModal组件。虽然React中没有类似Vue官方定义的标签,但是我们可以自己实现,也可以借助第三方组件实现。