成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Ant Design源碼分析(三):Wave組件

luzhuqun / 3603人閱讀

摘要:返回刪除的節(jié)點。組件運行邏輯此時,組件的代碼與邏輯已經(jīng)全部分析完了,整個組件的運行邏輯可以通過下方這張圖來概括本篇完

Wave組件效果預(yù)覽

???????在上一篇文章Button組件的源碼分析中遇到了一個Wave組件, Wave組件在Ant design中提供了通用的表單控件點擊效果,在自己閱讀源碼之前,也并沒有過更多留心過在這些表單控件的動畫效果是如何實現(xiàn)的,甚至可能有時都沒注意到這些動畫效果。下面先一起來看以下具體的效果(留意邊框以外,一閃一閃的波浪動畫效果):

Button組件

Radio組件

Switch組件

???????看完UI效果之后我們大概已經(jīng)知道是什么了,再看代碼部分,由于代碼書寫順序與閱讀順序并不一致,為了方便理解,我們在分析源碼的過程中,會調(diào)整代碼解釋的順序

源碼分析
// 一個新的依賴,暫時不知道是什么,依據(jù)名字推測與動畫效果有關(guān)
import TransitionEvents from "css-animation/lib/Event";

export default class Wave extends React.Component<{insertExtraNode?: boolean}> {
  
  //... some type code
  
  // 我們發(fā)現(xiàn)Wave組件只提供組件邏輯,不參與UI展示,這種容器組件,往往在DidMount或WillMount聲明周期中開始
  // 構(gòu)建組件邏輯,往下看
  render() {
    return this.props.children;
  }
  
  // 只有一行代碼, 先看下方bindAnimationEvent方法
  componentDidMount() {
    this.instance = this.bindAnimationEvent(findDOMNode(this) as HTMLElement);
  }
    
  // 在組件卸載時,清除掉事件監(jiān)聽與定時器,避免內(nèi)存泄漏
  componentWillUnmount() {
    if (this.instance) {
      this.instance.cancel();
    }
    if (this.clickWaveTimeoutId) {
      clearTimeout(this.clickWaveTimeoutId);
    }
  }  

  // 根據(jù)名字推測: 為DOM節(jié)點綁定動畫效果,進入函數(shù)內(nèi)部查看
  bindAnimationEvent = (node: HTMLElement) => {
   //... some code 

    const onClick = (e: MouseEvent) => {
      //... some code

      // 無論是否正在執(zhí)行動畫,先清除掉動畫效果(至于怎么清除,先不關(guān)注)
      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);
    };
  
    // 監(jiān)聽node(this.props.children)的onClick事件
    node.addEventListener("click", onClick, true);

    // 將移除監(jiān)聽事件的回調(diào)函數(shù)封裝在一個對象中并作為返回值,看著這里應(yīng)該想起之前定義的私有變量instance,
    // 回顧DidMount生命周期函數(shù),你會發(fā)現(xiàn)這個返回的對象將會被儲存在instance中
    return {
      cancel: () => {
        node.removeEventListener("click", onClick, true);
      },
    };
  }

  //未完待續(xù)

我們通過觀察上方bindAnimationEvent方法,其主要做了三件事,調(diào)用了兩個外部函數(shù)this.resetEffectthis.onClick
1、過濾不執(zhí)行的條件(代碼省略掉了,非主干邏輯)
2、聲明onClick函數(shù),并作為node的點擊事件觸發(fā)時要執(zhí)行的函數(shù)
3、返回一個儲存了取消監(jiān)聽click事件方法的對象

個人認(rèn)為bindAnimationEvent方法,做了太多的事情,而ComponentDidMount做的事情太少(單一原則)
往下方,繼續(xù)查看 this.resetEffectthis.onClick 分別是做什么的,以及如何實現(xiàn)的

  // 這個函數(shù)是實現(xiàn)動畫效果的核心,其主要有三個行為:1、創(chuàng)建內(nèi)聯(lián)style標(biāo)簽, 2、插入css字符串 3、并將其插入到document中
  // 我們知道css也是可以控制DOM變化的,比如偽類元素:after :before  這里正是通過:after來實現(xiàn)效果的
  onClick = (node: HTMLElement, waveColor: string) => {
    //... some code 1
    const { insertExtraNode } = this.props;

    /* 創(chuàng)建了一個div元素extraNode,裝飾該div,在inserExtracNode= true時,將extraNode作為node的子元素 */
    /* 創(chuàng)建一個div元素,并緩存中私有變量extraNode中 */
    this.extraNode = document.createElement("div");
    
    /* 這里用let 更合適 */
    const extraNode = this.extraNode;
    extraNode.className = "ant-click-animating-node";
    // 可能有人好奇這個extraNode是干嘛的?
    // 往之后的代碼中看的時候會發(fā)現(xiàn),在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:這里創(chuàng)建了一個內(nèi)聯(lián)style標(biāo)簽
    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:在內(nèi)聯(lián)style標(biāo)簽中插入樣式字符串, 利用偽元素:after作為承載效果的DOM */
        styleForPesudo.innerHTML =
            `[ant-click-animating-without-extra-node]:after { border-color: ${waveColor}; }`;
            
        /* 行為3:將style標(biāo)簽插入到document中 */
      if (!document.body.contains(styleForPesudo)) {
        document.body.appendChild(styleForPesudo);
      }
    }    

     /* 在inserExtarNode為true時,將extraNode插入到node子元素中 */
    if (insertExtraNode) {
      node.appendChild(extraNode);
    }
    
    /* 為元素增加動畫效果 */
    TransitionEvents.addEndEventListener(node, this.onTransitionEnd);
  }

  /**
   * 重置效果
   * 顧名思義:這個函數(shù)通過三個行為,致力于一件事情,取消動畫效果
   * 1、刪除node的attribute屬性 2、node的子元素 3、刪除對應(yīng)的內(nèi)聯(lián)style標(biāo)簽
   */
  resetEffect(node: HTMLElement) {
    // come code ...
    
    const { insertExtraNode } = this.props;
    
    const attributeName = this.getAttributeName();
    /* 行為1:刪除node的attribute屬性 */
    node.removeAttribute(attributeName);

    /* 行為3: 清空了為偽類元素內(nèi)置的style標(biāo)簽 styleForPesudo */
    this.removeExtraStyleNode();

    if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) {
      // Node.removeChild() 方法從DOM中刪除一個子節(jié)點。返回刪除的節(jié)點。
      node.removeChild(this.extraNode);
    }
    TransitionEvents.removeEndEventListener(node, this.onTransitionEnd);
  }

  // 刪除內(nèi)聯(lián)style標(biāo)簽
  removeExtraStyleNode() {
    if (styleForPesudo) {
      styleForPesudo.innerHTML = "";
    }
  }
      
  // 在每次動畫執(zhí)行結(jié)束后,清除掉狀態(tài),完成一個生命周期
  onTransitionEnd = (e: AnimationEvent) => {
    // todo
    if (!e || e.animationName !== "fadeEffect") {
      return;
    }

    this.resetEffect(e.target as HTMLElement);
  }

}
組件邏輯:

我們回過頭來看第一部分的代碼,組件邏輯體現(xiàn)在componentDidMountcomponentWillUnMount
1、在componentDidMount中為this.props.childrenclick事件綁定動畫執(zhí)行函數(shù)this.onClick,
2、在componentWillUnMount中清除與動畫相關(guān)的狀態(tài)避免內(nèi)存泄漏。

組件運行邏輯:

此時,Wave組件的代碼與邏輯已經(jīng)全部分析完了,整個Wave組件的運行邏輯可以通過下方這張圖來概括

本篇完~

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102079.html

相關(guān)文章

  • Ant design的Notification源碼分析

    摘要:通過將實例傳入回調(diào)函數(shù)。添加再回過頭來看回調(diào)函數(shù)的內(nèi)容。其中的作用是一次調(diào)用傳入的各函數(shù),其中方法是移除中相應(yīng)的節(jié)點,是傳入的關(guān)閉標(biāo)簽后的回調(diào)函數(shù)。 notification簡介 showImg(https://segmentfault.com/img/remote/1460000014117558?w=483&h=135); notification就是通知提醒框,在系統(tǒng)四個角顯示通...

    SimpleTriangle 評論0 收藏0
  • Ant-Design-組件-——-Form表單(一)

    摘要:擅長網(wǎng)站建設(shè)微信公眾號開發(fā)微信小程序開發(fā)小游戲制作企業(yè)微信制作建設(shè),專注于前端框架服務(wù)端渲染技術(shù)交互設(shè)計圖像繪制數(shù)據(jù)分析等研究。 Ant Design of React @3.10.9 拉取項目 luwei.web.study-ant-design-pro, 切換至 query 分支,可看到 Form 表單實現(xiàn)效果 實現(xiàn)一個查詢表單 showImg(https://segmentfau...

    trilever 評論0 收藏0
  • 前端最實用書簽(持續(xù)更新)

    摘要:前言一直混跡社區(qū)突然發(fā)現(xiàn)自己收藏了不少好文但是管理起來有點混亂所以將前端主流技術(shù)做了一個書簽整理不求最多最全但求最實用。 前言 一直混跡社區(qū),突然發(fā)現(xiàn)自己收藏了不少好文但是管理起來有點混亂; 所以將前端主流技術(shù)做了一個書簽整理,不求最多最全,但求最實用。 書簽源碼 書簽導(dǎo)入瀏覽器效果截圖showImg(https://segmentfault.com/img/bVbg41b?w=107...

    sshe 評論0 收藏0
  • TypeScript 、React、 Redux和Ant-Design的最佳實踐

    摘要:使用官方的的另外一種版本和一起使用自動配置了一個項目支持。需要的依賴都在文件中。帶靜態(tài)類型檢驗,現(xiàn)在的第三方包基本上源碼都是,方便查看調(diào)試。大型項目首選和結(jié)合,代碼調(diào)試維護起來極其方便。 showImg(https://segmentfault.com/img/bVbrTKz?w=1400&h=930); 阿特伍德定律,指的是any application that can be wr...

    wangbinke 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<