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

我们在写一些 UI 组件时,若不考虑动效,就很容易实现,主要就是有无的切换(类似于 Vue 中的 v-if 属性)或者可见性的切换(类似于 Vue 中的 v-show 属性)。

成都创新互联公司主营崇州网站建设的网络公司,主营网站建设方案,app软件定制开发,崇州h5小程序开发搭建,崇州网站营销推广欢迎崇州等地区企业咨询

1. 没有动效的弹窗

在 React 中,可以这样来实现:

 
 
 
 
  1. interface ModalProps {
  2.   open: boolean;
  3.   onClose?: () => void;
  4.   children?: any;
  5. }
  6. const Modal = ({open. onClose, children}: ModalProps) => {
  7.   if (!open) {
  8.     return null;
  9.   }
  10.   return createPortal(
  11.     {children}
  •     x
  •   
  • , document.body);
  • };
  • 使用方式:

     
     
     
     
    1. const App = () => {
    2.   const [open, setOpen] = useState(false);
    3.   return (
    4.     
    5.        setOpen(true)}>show modal
    6.        setOpen(false)}>
    7.         modal content
    8.       
    9.     
    10.   );
    11. };

    我们在这里就是使用 open 属性来控制展示还是不展示,但完全没有渐变的效果。

    若我们想实现 fade, zoom 等动画效果,还需要对此进行改造。

    2. 自己动手实现有动效的弹窗

    很多同学在自己实现动效时,经常是展示的时候有动效,关闭的时候没有动效。都是动效的时机没有控制好。这里我们先自己来实现一下动效的流转。

    刚开始我实现的时候,动效只有开始状态和结束状态,需要很多的变量和逻辑来控制这个动效。

    后来我参考了 react-transition-group 组件的实现,他是将动效拆分成了几个部分,每个部分分别进行控制。

    动效过程在 enter-active 和 exit-active 的过程中。

    我们再通过一个变量 active 来控制是关闭动效是否已执行关闭,参数 open 只控制是执行展开动效还是关闭动效。

    当 open 和 active 都为 false 时,才销毁弹窗。

     
     
     
     
    1. const Modal = ({ open, children, onClose }) => {
    2.   const [active, setActive] = useState(false); // 弹窗的存在周期
    3.   if (!open && !active) {
    4.     return null;
    5.   }
    6.   return ReactDOM.createPortal(
    7.     
    8.       {children}
    9.       
    10.         x
    11.       
    12.     ,
    13.     document.body,
    14.   );
    15. };

    这里我们接着添加动效过程的变化:

     
     
     
     
    1. const [aniClassName, setAniClassName] = useState(''); // 动效的class
    2. // transition执行完毕的监听函数
    3. const onTransitionEnd = () => {
    4.   // 当open为rue时,则结束状态为'enter-done'
    5.   // 当open未false时,则结束状态为'exit-done'
    6.   setAniClassName(open ? 'enter-done' : 'exit-done');
    7.   // 若open为false,则动画结束时,弹窗的生命周期结束
    8.   if (!open) {
    9.     setActive(false);
    10.   }
    11. };
    12. useEffect(() => {
    13.   if (open) {
    14.     setActive(true);
    15.     setAniClassName('enter');
    16.     // setTimeout用来切换class,让transition动起来
    17.     setTimeout(() => {
    18.       setAniClassName('enter-active');
    19.     });
    20.   } else {
    21.     setAniClassName('exit');
    22.     setTimeout(() => {
    23.       setAniClassName('exit-active');
    24.     });
    25.   }
    26. }, [open]);

    Modal 组件完整的代码如下:

     
     
     
     
    1. const Modal = ({ open, children, onClose }) => {
    2.   const [active, setActive] = useState(false); // 弹窗的存在周期
    3.   const [aniClassName, setAniClassName] = useState(''); // 动效的class
    4.   const onTransitionEnd = () => {
    5.     setAniClassName(open ? 'enter-done' : 'exit-done');
    6.     if (!open) {
    7.       setActive(false);
    8.     }
    9.   };
    10.   useEffect(() => {
    11.     if (open) {
    12.       setActive(true);
    13.       setAniClassName('enter');
    14.       setTimeout(() => {
    15.         setAniClassName('enter-active');
    16.       });
    17.     } else {
    18.       setAniClassName('exit');
    19.       setTimeout(() => {
    20.         setAniClassName('exit-active');
    21.       });
    22.     }
    23.   }, [open]);
    24.   if (!open && !active) {
    25.     return null;
    26.   }
    27.   return ReactDOM.createPortal(
    28.     
    29.       {children}
    30.       
    31.         x
    32.       
    33.     ,
    34.     document.body,
    35.   );
    36. };

    动效的流转过程已经实现了,样式也要一起写上。比如我们要实现渐隐渐现的 fade 效果:

     
     
     
     
    1. .enter {
    2.   opacity: 0;
    3. }
    4. .enter-active {
    5.   transition: opacity 200ms ease-in-out;
    6.   opacity: 1;
    7. }
    8. .enter-done {
    9.   opacity: 1;
    10. }
    11. .exit {
    12.   opacity: 1;
    13. }
    14. .exit-active {
    15.   opacity: 0;
    16.   transition: opacity 200ms ease-in-out;
    17. }
    18. .exit-done {
    19.   opacity: 0;
    20. }

    如果是要实现放大缩小的 zoom 效果,修改这几个 class 就行。

    一个带有动效的弹窗就已经实现了。

    使用方式:

     
     
     
     
    1. const App = () => {
    2.   const [open, setOpen] = useState(false);
    3.   return (
    4.     
    5.        setOpen(true)}>show modal
    6.        setOpen(false)}>
    7.         modal content
    8.       
    9.     
    10.   );
    11. };

    类似地,还有 Toast 之类的,也可以这样实现。

    3. react-transition-group

    我们在实现动效的思路上借鉴了 react-transition-group 中的 CSSTransition 组件。 CSSTransition 已经帮我封装好了动效展开和关闭的过程,我们在实现弹窗时,可以直接使用该组件。

    这里有一个重要的属性: unmountOnExit ,表示在动效结束后,卸载该组件。

     
     
     
     
    1. const Modal = ({ open, onClose }) => {
    2.   // http://reactcommunity.org/react-transition-group/css-transition/
    3.   // in属性为true/false,true为展开动效,false为关闭动效
    4.   return createPortal(
    5.     
    6.       
    7.         {children}
    8.         
    9.           x
    10.         
    11.       
    12.     ,
    13.     document.body,
    14.   );
    15. };

    在使用 CSSTransition 组件后,Modal 的动效就方便多了。

    4. 总结

    至此已把待动效的 React Modal 组件实现出来了。虽然 React 中没有类似 Vue 官方定义的  标签,不过我们可以自己或者借助第三方组件来实现。

    网站题目:实现一个带有动效的React弹窗组件
    URL链接:http://www.shufengxianlan.com/qtweb/news29/43529.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

    猜你还喜欢下面的内容

    python知识

    行业网站建设