成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

實現一個帶有動效的 React 彈窗組件

開發 前端
雖然 React 中沒有類似 Vue 官方定義的<transition>標簽,不過我們可以自己或者借助第三方組件來實現。

[[406647]]

我們在寫一些 UI 組件時,若不考慮動效,就很容易實現,主要就是有無的切換(類似于 Vue 中的 v-if 屬性)或者可見性的切換(類似于 Vue 中的 v-show 屬性)。

[[406648]]

1. 沒有動效的彈窗

在 React 中,可以這樣來實現:

  1. interface ModalProps { 
  2.   open: boolean
  3.   onClose?: () => void
  4.   children?: any; 
  5. const Modal = ({open. onClose, children}: ModalProps) => { 
  6.   if (!open) { 
  7.     return null
  8.   } 
  9.   return createPortal(<div> 
  10.     <div className="modal-content">{children}</div> 
  11.     <div className="modal-close-btn" onClick={onClose}>x</div> 
  12.   </div>, document.body); 
  13. }; 

使用方式:

  1. const App = () => { 
  2.   const [open, setOpen] = useState(false); 
  3.  
  4.   return ( 
  5.     <div className="app"
  6.       <button onClick={() => setOpen(true)}>show modal</button> 
  7.       <Modal open={open} onClose={() => setOpen(false)}> 
  8.         modal content 
  9.       </Modal> 
  10.     </div> 
  11.   ); 
  12. }; 

我們在這里就是使用 open 屬性來控制展示還是不展示,但完全沒有漸變的效果。

若我們想實現 fade, zoom 等動畫效果,還需要對此進行改造。

[[406649]]

2. 自己動手實現有動效的彈窗

很多同學在自己實現動效時,經常是展示的時候有動效,關閉的時候沒有動效。都是動效的時機沒有控制好。這里我們先自己來實現一下動效的流轉。

剛開始我實現的時候,動效只有開始狀態和結束狀態,需要很多的變量和邏輯來控制這個動效。

后來我參考了 react-transition-group 組件的實現,他是將動效拆分成了幾個部分,每個部分分別進行控制。

  • 展開動效的順序:enter -> enter-active -> enter-done;

  • 關閉動效的順序:exit -> exit-active -> exit-done;

動效過程在 enter-active 和 exit-active 的過程中。

我們再通過一個變量 active 來控制是關閉動效是否已執行關閉,參數 open 只控制是執行展開動效還是關閉動效。

當 open 和 active 都為 false 時,才銷毀彈窗。

  1. const Modal = ({ open, children, onClose }) => { 
  2.   const [active, setActive] = useState(false); // 彈窗的存在周期 
  3.  
  4.   if (!open && !active) { 
  5.     return null
  6.   } 
  7.  
  8.   return ReactDOM.createPortal( 
  9.     <div className="modal"
  10.       <div className="modal-content">{children}</div> 
  11.       <div className="modal-close-btn" onClick={onClose}> 
  12.         x 
  13.       </div> 
  14.     </div>, 
  15.     document.body, 
  16.   ); 
  17. }; 

這里我們接著添加動效過程的變化:

  1. const [aniClassName, setAniClassName] = useState(''); // 動效的class 
  2.  
  3. // transition執行完畢的監聽函數 
  4. const onTransitionEnd = () => { 
  5.   // 當open為rue時,則結束狀態為'enter-done' 
  6.   // 當open未false時,則結束狀態為'exit-done' 
  7.   setAniClassName(open ? 'enter-done' : 'exit-done'); 
  8.  
  9.   // 若open為false,則動畫結束時,彈窗的生命周期結束 
  10.   if (!open) { 
  11.     setActive(false); 
  12.   } 
  13. }; 
  14.  
  15. useEffect(() => { 
  16.   if (open) { 
  17.     setActive(true); 
  18.     setAniClassName('enter'); 
  19.     // setTimeout用來切換class,讓transition動起來 
  20.     setTimeout(() => { 
  21.       setAniClassName('enter-active'); 
  22.     }); 
  23.   } else { 
  24.     setAniClassName('exit'); 
  25.     setTimeout(() => { 
  26.       setAniClassName('exit-active'); 
  27.     }); 
  28.   } 
  29. }, [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.  
  11.   useEffect(() => { 
  12.     if (open) { 
  13.       setActive(true); 
  14.       setAniClassName('enter'); 
  15.       setTimeout(() => { 
  16.         setAniClassName('enter-active'); 
  17.       }); 
  18.     } else { 
  19.       setAniClassName('exit'); 
  20.       setTimeout(() => { 
  21.         setAniClassName('exit-active'); 
  22.       }); 
  23.     } 
  24.   }, [open]); 
  25.  
  26.   if (!open && !active) { 
  27.     return null
  28.   } 
  29.  
  30.   return ReactDOM.createPortal( 
  31.     <div className={'modal ' + aniClassName} onTransitionEnd={onTransitionEnd}> 
  32.       <div className="modal-content">{children}</div> 
  33.       <div className="modal-close-btn" onClick={onClose}> 
  34.         x 
  35.       </div> 
  36.     </div>, 
  37.     document.body, 
  38.   ); 
  39. }; 

動效的流轉過程已經實現了,樣式也要一起寫上。比如我們要實現漸隱漸現的 fade 效果:

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

如果是要實現放大縮小的 zoom 效果,修改這幾個 class 就行。

一個帶有動效的彈窗就已經實現了。

使用方式:

  1. const App = () => { 
  2.   const [open, setOpen] = useState(false); 
  3.  
  4.   return ( 
  5.     <div className="app"
  6.       <button onClick={() => setOpen(true)}>show modal</button> 
  7.       <Modal open={open} onClose={() => setOpen(false)}> 
  8.         modal content 
  9.       </Modal> 
  10.     </div> 
  11.   ); 
  12. }; 

類似地,還有 Toast 之類的,也可以這樣實現。

[[406650]]

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.     <CSSTransition in={open} timeout={200} unmountOnExit> 
  6.       <div className="modal"
  7.         <div className="modal-content">{children}</div> 
  8.         <div className="modal-close-btn" onClick={onClose}> 
  9.           x 
  10.         </div> 
  11.       </div> 
  12.     </CSSTransition>, 
  13.     document.body, 
  14.   ); 
  15. }; 

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

4. 總結

至此已把待動效的 React Modal 組件實現出來了。雖然 React 中沒有類似 Vue 官方定義的 <transition> 標簽,不過我們可以自己或者借助第三方組件來實現。 

 

責任編輯:張燕妮 來源: 蚊子前端博客
相關推薦

2021-03-31 08:01:24

React Portareactcss3

2021-04-15 07:50:45

Veu 動效Vue應用程序

2023-09-05 20:17:18

typescriptPropTypesreact

2023-04-28 09:30:40

vuereact

2021-10-17 20:37:44

組件DrawerReact

2025-05-13 08:20:00

Vue3前端動效組件庫

2022-03-31 07:46:17

CSS動畫技巧

2019-07-24 09:00:19

谷歌Android開發者

2022-06-06 09:28:36

ReactHook

2024-03-20 09:31:00

圖片懶加載性能優化React

2023-06-05 15:00:13

書籍翻頁動效鴻蒙

2015-07-31 11:40:36

動效Swift

2021-01-28 06:11:40

導航組件Sidenav Javascript

2017-03-28 21:03:35

代碼React.js

2023-05-17 10:05:35

組件設計(Modal)組件

2023-12-01 11:10:13

CMS開源

2023-07-14 07:23:21

ReactuseEffect

2017-03-23 10:21:57

CSS3動效庫前端

2015-08-03 10:40:45

動效設計優勢

2022-01-17 11:41:50

前端Vite組件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 免费精品国产 | 国产91精品久久久久久久网曝门 | 国产精品无码专区在线观看 | 99久久婷婷国产综合精品首页 | 国产精品视频免费观看 | 欧美在线观看一区二区 | 亚洲激情在线观看 | 国产一区二区 | 久色| 欧美日韩在线观看视频网站 | 日本高清在线一区 | 久久久久久国产精品mv | 亚洲天堂色 | 欧美成人在线网站 | 免费一区在线观看 | 国产乱码一二三区精品 | 一级片毛片 | 亚洲国产一区二区在线 | 99色播 | 日韩成人| 性色网站 | 欧美在线视频观看 | 日韩一区二区免费视频 | 欧美激情网站 | 久久久999成人 | 亚洲一区二区电影网 | 亚洲国产自产 | 日韩一区二区不卡 | 中文字幕视频在线观看 | 亚洲免费一区二区 | 精品国产乱码久久久久久蜜柚 | 午夜激情视频在线 | 欧美日韩黄色一级片 | 久久久久久www | 91就要激情 | 色综网| 青青草社区 | 国产精品一区二区在线 | 欧美日韩在线观看视频网站 | 亚洲欧美中文日韩在线v日本 | 在线观看亚洲精品视频 |