摘要:返回刪除的節點。組件運行邏輯此時,組件的代碼與邏輯已經全部分析完了,整個組件的運行邏輯可以通過下方這張圖來概括本篇完
Wave組件效果預覽
???????在上一篇文章Button組件的源碼分析中遇到了一個Wave組件, Wave組件在Ant design中提供了通用的表單控件點擊效果,在自己閱讀源碼之前,也并沒有過更多留心過在這些表單控件的動畫效果是如何實現的,甚至可能有時都沒注意到這些動畫效果。下面先一起來看以下具體的效果(留意邊框以外,一閃一閃的波浪動畫效果):
Button組件
Radio組件
Switch組件
???????看完UI效果之后我們大概已經知道是什么了,再看代碼部分,由于代碼書寫順序與閱讀順序并不一致,為了方便理解,我們在分析源碼的過程中,會調整代碼解釋的順序
源碼分析// 一個新的依賴,暫時不知道是什么,依據名字推測與動畫效果有關 import TransitionEvents from "css-animation/lib/Event"; export default class Wave extends React.Component<{insertExtraNode?: boolean}> { //... some type code // 我們發現Wave組件只提供組件邏輯,不參與UI展示,這種容器組件,往往在DidMount或WillMount聲明周期中開始 // 構建組件邏輯,往下看 render() { return this.props.children; } // 只有一行代碼, 先看下方bindAnimationEvent方法 componentDidMount() { this.instance = this.bindAnimationEvent(findDOMNode(this) as HTMLElement); } // 在組件卸載時,清除掉事件監聽與定時器,避免內存泄漏 componentWillUnmount() { if (this.instance) { this.instance.cancel(); } if (this.clickWaveTimeoutId) { clearTimeout(this.clickWaveTimeoutId); } } // 根據名字推測: 為DOM節點綁定動畫效果,進入函數內部查看 bindAnimationEvent = (node: HTMLElement) => { //... some code const onClick = (e: MouseEvent) => { //... some code // 無論是否正在執行動畫,先清除掉動畫效果(至于怎么清除,先不關注) this.resetEffect(node); // 從target取得顏色值 const waveColor = getComputedStyle(node).getPropertyValue("border-top-color") || // Firefox Compatible getComputedStyle(node).getPropertyValue("border-color") || getComputedStyle(node).getPropertyValue("background-color"); // 在這里可以看到之前定義的私有變量clickWaveTimeoutId,被用作儲存一個定時器 this.clickWaveTimeoutId = window.setTimeout(() => this.onClick(node, waveColor), 0); }; // 監聽node(this.props.children)的onClick事件 node.addEventListener("click", onClick, true); // 將移除監聽事件的回調函數封裝在一個對象中并作為返回值,看著這里應該想起之前定義的私有變量instance, // 回顧DidMount生命周期函數,你會發現這個返回的對象將會被儲存在instance中 return { cancel: () => { node.removeEventListener("click", onClick, true); }, }; } //未完待續
我們通過觀察上方bindAnimationEvent方法,其主要做了三件事,調用了兩個外部函數this.resetEffect 與 this.onClick
1、過濾不執行的條件(代碼省略掉了,非主干邏輯)
2、聲明onClick函數,并作為node的點擊事件觸發時要執行的函數
3、返回一個儲存了取消監聽click事件方法的對象
個人認為bindAnimationEvent方法,做了太多的事情,而ComponentDidMount做的事情太少(單一原則)
往下方,繼續查看 this.resetEffect 與 this.onClick 分別是做什么的,以及如何實現的
// 這個函數是實現動畫效果的核心,其主要有三個行為:1、創建內聯style標簽, 2、插入css字符串 3、并將其插入到document中 // 我們知道css也是可以控制DOM變化的,比如偽類元素:after :before 這里正是通過:after來實現效果的 onClick = (node: HTMLElement, waveColor: string) => { //... some code 1 const { insertExtraNode } = this.props; /* 創建了一個div元素extraNode,裝飾該div,在inserExtracNode= true時,將extraNode作為node的子元素 */ /* 創建一個div元素,并緩存中私有變量extraNode中 */ this.extraNode = document.createElement("div"); /* 這里用let 更合適 */ const extraNode = this.extraNode; extraNode.className = "ant-click-animating-node"; // 可能有人好奇這個extraNode是干嘛的? // 往之后的代碼中看的時候會發現,在insertExtraNode為false時,Wave通過插入偽類元素:after 來作為承載動畫效果的DOM元素 // 在insertExtraNode = true時,會生成一個div替代:after偽類元素,猜測是某些this.props.children可能自帶:after,所以 // 使用div元素來替代:after避免沖突,在這里我們只需要知道它是作為承載動畫css的DOM元素即可 // 獲取指定的string insertExtraNode ? "ant-click-animating" : "ant-click-animating-without-extra-node"; const attributeName = this.getAttributeName(); // Element.removeAttribute("someString"); 從element中刪除值為someString的屬性 // Element.setAttribute(name, value); 為element元素值為value的name屬性 node.removeAttribute(attributeName); node.setAttribute(attributeName, "true"); // 行為1:這里創建了一個內聯style標簽 styleForPesudo = styleForPesudo || document.createElement("style"); if (waveColor && waveColor !== "#ffffff" && waveColor !== "rgb(255, 255, 255)" && this.isNotGrey(waveColor) && /* 透明度不為0的任意顏色 */ !/rgba(d*, d*, d*, 0)/.test(waveColor) && // any transparent rgba color waveColor !== "transparent") { /* 給子元素加上borderColor */ extraNode.style.borderColor = waveColor; /* 行為2:在內聯style標簽中插入樣式字符串, 利用偽元素:after作為承載效果的DOM */ styleForPesudo.innerHTML = `[ant-click-animating-without-extra-node]:after { border-color: ${waveColor}; }`; /* 行為3:將style標簽插入到document中 */ if (!document.body.contains(styleForPesudo)) { document.body.appendChild(styleForPesudo); } } /* 在inserExtarNode為true時,將extraNode插入到node子元素中 */ if (insertExtraNode) { node.appendChild(extraNode); } /* 為元素增加動畫效果 */ TransitionEvents.addEndEventListener(node, this.onTransitionEnd); } /** * 重置效果 * 顧名思義:這個函數通過三個行為,致力于一件事情,取消動畫效果 * 1、刪除node的attribute屬性 2、node的子元素 3、刪除對應的內聯style標簽 */ resetEffect(node: HTMLElement) { // come code ... const { insertExtraNode } = this.props; const attributeName = this.getAttributeName(); /* 行為1:刪除node的attribute屬性 */ node.removeAttribute(attributeName); /* 行為3: 清空了為偽類元素內置的style標簽 styleForPesudo */ this.removeExtraStyleNode(); if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) { // Node.removeChild() 方法從DOM中刪除一個子節點。返回刪除的節點。 node.removeChild(this.extraNode); } TransitionEvents.removeEndEventListener(node, this.onTransitionEnd); } // 刪除內聯style標簽 removeExtraStyleNode() { if (styleForPesudo) { styleForPesudo.innerHTML = ""; } } // 在每次動畫執行結束后,清除掉狀態,完成一個生命周期 onTransitionEnd = (e: AnimationEvent) => { // todo if (!e || e.animationName !== "fadeEffect") { return; } this.resetEffect(e.target as HTMLElement); } }組件邏輯:
我們回過頭來看第一部分的代碼,組件邏輯體現在componentDidMount 與 componentWillUnMount中
1、在componentDidMount中為this.props.children的click事件綁定動畫執行函數this.onClick,
2、在componentWillUnMount中清除與動畫相關的狀態避免內存泄漏。
此時,Wave組件的代碼與邏輯已經全部分析完了,整個Wave組件的運行邏輯可以通過下方這張圖來概括
本篇完~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102079.html
摘要:通過將實例傳入回調函數。添加再回過頭來看回調函數的內容。其中的作用是一次調用傳入的各函數,其中方法是移除中相應的節點,是傳入的關閉標簽后的回調函數。 notification簡介 showImg(https://segmentfault.com/img/remote/1460000014117558?w=483&h=135); notification就是通知提醒框,在系統四個角顯示通...
摘要:擅長網站建設微信公眾號開發微信小程序開發小游戲制作企業微信制作建設,專注于前端框架服務端渲染技術交互設計圖像繪制數據分析等研究。 Ant Design of React @3.10.9 拉取項目 luwei.web.study-ant-design-pro, 切換至 query 分支,可看到 Form 表單實現效果 實現一個查詢表單 showImg(https://segmentfau...
摘要:前言一直混跡社區突然發現自己收藏了不少好文但是管理起來有點混亂所以將前端主流技術做了一個書簽整理不求最多最全但求最實用。 前言 一直混跡社區,突然發現自己收藏了不少好文但是管理起來有點混亂; 所以將前端主流技術做了一個書簽整理,不求最多最全,但求最實用。 書簽源碼 書簽導入瀏覽器效果截圖showImg(https://segmentfault.com/img/bVbg41b?w=107...
摘要:使用官方的的另外一種版本和一起使用自動配置了一個項目支持。需要的依賴都在文件中。帶靜態類型檢驗,現在的第三方包基本上源碼都是,方便查看調試。大型項目首選和結合,代碼調試維護起來極其方便。 showImg(https://segmentfault.com/img/bVbrTKz?w=1400&h=930); 阿特伍德定律,指的是any application that can be wr...
閱讀 920·2021-11-16 11:45
閱讀 2126·2021-10-09 09:44
閱讀 1340·2019-08-30 14:03
閱讀 1126·2019-08-26 18:28
閱讀 3328·2019-08-26 13:50
閱讀 1715·2019-08-23 18:38
閱讀 3450·2019-08-23 18:22
閱讀 3589·2019-08-23 15:27