自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

實現(xiàn)一個帶有動效的 React 彈窗組件

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

[[406647]]

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

[[406648]]

1. 沒有動效的彈窗

在 React 中,可以這樣來實現(xiàn):

  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 屬性來控制展示還是不展示,但完全沒有漸變的效果。

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

[[406649]]

2. 自己動手實現(xiàn)有動效的彈窗

很多同學在自己實現(xiàn)動效時,經(jīng)常是展示的時候有動效,關(guān)閉的時候沒有動效。都是動效的時機沒有控制好。這里我們先自己來實現(xiàn)一下動效的流轉(zhuǎn)。

剛開始我實現(xiàn)的時候,動效只有開始狀態(tài)和結(jié)束狀態(tài),需要很多的變量和邏輯來控制這個動效。

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

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

  • 關(guān)閉動效的順序:exit -> exit-active -> exit-done;

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

我們再通過一個變量 active 來控制是關(guān)閉動效是否已執(zhí)行關(guān)閉,參數(shù) open 只控制是執(zhí)行展開動效還是關(guān)閉動效。

當 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執(zhí)行完畢的監(jiān)聽函數(shù) 
  4. const onTransitionEnd = () => { 
  5.   // 當open為rue時,則結(jié)束狀態(tài)為'enter-done' 
  6.   // 當open未false時,則結(jié)束狀態(tài)為'exit-done' 
  7.   setAniClassName(open ? 'enter-done' : 'exit-done'); 
  8.  
  9.   // 若open為false,則動畫結(jié)束時,彈窗的生命周期結(jié)束 
  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. }; 

動效的流轉(zhuǎn)過程已經(jīng)實現(xiàn)了,樣式也要一起寫上。比如我們要實現(xiàn)漸隱漸現(xiàn)的 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

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

一個帶有動效的彈窗就已經(jīng)實現(xiàn)了。

使用方式:

  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 之類的,也可以這樣實現(xiàn)。

[[406650]]

3. react-transition-group

我們在實現(xiàn)動效的思路上借鑒了 react-transition-group 中的 CSSTransition 組件。 CSSTransition 已經(jīng)幫我封裝好了動效展開和關(guān)閉的過程,我們在實現(xiàn)彈窗時,可以直接使用該組件。

這里有一個重要的屬性: unmountOnExit ,表示在動效結(jié)束后,卸載該組件。

  1. const Modal = ({ open, onClose }) => { 
  2.   // http://reactcommunity.org/react-transition-group/css-transition/ 
  3.   // in屬性為true/false,true為展開動效,false為關(guān)閉動效 
  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. 總結(jié)

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

 

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

2021-04-15 07:50:45

Veu 動效Vue應用程序

2021-03-31 08:01:24

React Portareactcss3

2023-09-05 20:17:18

typescriptPropTypesreact

2023-04-28 09:30:40

vuereact

2021-10-17 20:37:44

組件DrawerReact

2022-03-31 07:46:17

CSS動畫技巧

2022-06-06 09:28:36

ReactHook

2019-07-24 09:00:19

谷歌Android開發(fā)者

2023-06-05 15:00:13

書籍翻頁動效鴻蒙

2024-03-20 09:31:00

圖片懶加載性能優(yōu)化React

2017-03-28 21:03:35

代碼React.js

2015-07-31 11:40:36

動效Swift

2023-12-01 11:10:13

CMS開源

2023-07-14 07:23:21

ReactuseEffect

2021-01-28 06:11:40

導航組件Sidenav Javascript

2023-05-17 10:05:35

組件設計(Modal)組件

2017-03-23 10:21:57

CSS3動效庫前端

2015-08-03 10:40:45

動效設計優(yōu)勢

2014-09-28 10:39:24

AppleWatchUI

2022-08-29 07:48:27

文件數(shù)據(jù)參數(shù)類型
點贊
收藏

51CTO技術(shù)棧公眾號