【組件2】對話框 - Dialog

確定API

  • 要確保你的API和同行的API沒有太大不同,否則用戶學習成本變高,不利于我們的UI使用;所以我們就可以去copy下同行的API;
  • 提供兩種風格:一是標簽風格,二是API風格
  • 創建dialog目錄;

搭建Dialog 基本架子

  • <Fragment></Fragment>用于把多個div包起來,但是在頁面中卻不會渲染出來(有點像<template>),所以經常使用<Fragment></Fragment>來代替<div></div>
  • 我們需要在每個className上都寫一遍dui-dialog-,豈不是很麻煩?!所以我們寫個函數來統一它吧~
  • 返回函數的函數叫做高階函數;

添加CSS

  • 這里一個小問題,index.scss要引入到example.tsx中樣式才有效!!!!只引入到index.tsx中在預覽例子的時候樣式不起作用!!!!(應該跟生產開發環境文件設置的入口有關)
  • 想要svg受外面字體顏色的控制,加上fill: currentColor;
  • 跟字體相關可以用px、em,跟布局寬度相關可以用min-width結合em;
  • 屬性選擇器[class^=xx]代表所有以xx開頭的類;

添加事件

1、可以自定義按鈕
  • 給dialog一個buttons Props,它是個數組;
  • 所以這時又有個小警告了,因為是個數組,需要給每一項設置key,就用到了React.cloneElement
  • 為什么用React.cloneElement,而不是直接button['key'] = index這樣添加屬性呢,因為報錯啊!!!說不能給只讀屬性key賦值啊!!!
2、給組件的props設置默認值
Dialog.defaultProps = {
  closeonClickMask: false
}
  • 一般設置過默認值后,這個props就是可選的,interface屬性那里加上?
3、ReactDOM.createPortal
  • ReactDOM.createPortal,這是由于層級問題引起的,給dialog的層級越小越好,這樣也方便用戶自己去改;
  • 一般網站架構師會設定好層級
  • 可以在文檔中告訴開發者,你如何寫可以覆蓋我的層級;


    image.png

注意:為了禁止遮罩層來回滑動,在對話框出現的時候document.body.style.overflow='hidden'document.body.style.paddingRight = '17px',關閉的時候恢復document.body.style.overflow='auto'document.body.style.paddingRight = '0'

給Dialog提供便利的API——alert

  • 動態創建組件,即用ReactDOM.render()把組件渲染進div;
  • 關閉組件呢,即還是用ReactDOM.render()渲染組件,只不過是把組件的visible屬性變成false;
  • ReactDOM.unmountComponentAtNode()文檔
//創建組件和節點
 const div = document.createElement("div");
  document.body.appendChild(div);
  document.body.style.overflow = 'hidden'
  ReactDOM.render(component, div);
//消除組件和節點
//第一句:把這個組件的visible改成false
ReactDOM.render(React.cloneElement(component, {visible: false}), div)
//第二句:把這個組件從div上卸載下來
ReactDOM.unmountComponentAtNode(div)
 document.body.style.overflow = 'auto'
//第三句:清除這個div
div.remove()

comfirm

modal

  • ReactElement和ReactNode區別:ReactElement只能是標簽元素,ReactNode還可以是字符串;
  • modal return一個函數出來,有點類似于閉包的形式;
  • 下面代碼中button調用函數的形式,要寫一個箭頭函數去調用close(這個close函數是modal()return出來的函數),直接onClick={close}的話是不可以的,因為解析器是從右往左執行的,這樣直接寫,它找不到你聲明的close在哪里,放在箭頭函數中就可以的原因是,函數是延遲執行的,只有點擊按鈕時才調用函數; 所以在聲明函數的時候不要直接去調用它本身!!!
const openModal = () => {
    const close = modal(
      <div>
        <h1>你好</h1>
        <button style={{ color: "purple" }} onClick={() => close()}>
          close
        </button>
      </div>
    );
  };

三者之前的區別

1、是否有按鈕
  • alert只有一個【確認】按鈕,按鈕沒有回調函數;
  • comfirm有【取消】、【確認】按鈕,且按鈕有各自的回調函數;
  • modal沒有按鈕;
2、傳的內容
  • alert和comfirm傳的內容僅僅是字符串;
  • modal不僅可以傳字符串,還可以傳元素,但要保證只有一個根元素;

重構

image.png
  • 寫完代碼請立即重構,消除重復的代碼;
  • 看上圖,抽出每個API中的part,可以看出它們的組成很相近,所以可以把它們寫成一個公共的函數;

總結

  • scopedClass 高階函數;
  • React.Fragment
  • 使用&&或者三元表達式來做條件判斷,一般不用if...else...來寫條件判斷,有點麻煩;
  • ReactDOM.createPortal傳送門,可以使元素脫離當前位置到達你指定的節點位置;
  • 如何動態去生成一個組件;
  • 閉包傳API;
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容