【組件2】對話框 - Dialog

確定API

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

搭建Dialog 基本架子

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

添加CSS

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

添加事件

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


    image.png

注意:為了禁止遮罩層來回滑動,在對話框出現(xiàn)的時(shí)候document.body.style.overflow='hidden'document.body.style.paddingRight = '17px',關(guān)閉的時(shí)候恢復(fù)document.body.style.overflow='auto'document.body.style.paddingRight = '0'

給Dialog提供便利的API——alert

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

comfirm

modal

  • ReactElement和ReactNode區(qū)別:ReactElement只能是標(biāo)簽元素,ReactNode還可以是字符串;
  • modal return一個(gè)函數(shù)出來,有點(diǎn)類似于閉包的形式;
  • 下面代碼中button調(diào)用函數(shù)的形式,要寫一個(gè)箭頭函數(shù)去調(diào)用close(這個(gè)close函數(shù)是modal()return出來的函數(shù)),直接onClick={close}的話是不可以的,因?yàn)榻馕銎魇菑挠彝髨?zhí)行的,這樣直接寫,它找不到你聲明的close在哪里,放在箭頭函數(shù)中就可以的原因是,函數(shù)是延遲執(zhí)行的,只有點(diǎn)擊按鈕時(shí)才調(diào)用函數(shù); 所以在聲明函數(shù)的時(shí)候不要直接去調(diào)用它本身?。?!
const openModal = () => {
    const close = modal(
      <div>
        <h1>你好</h1>
        <button style={{ color: "purple" }} onClick={() => close()}>
          close
        </button>
      </div>
    );
  };

三者之前的區(qū)別

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

重構(gòu)

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

總結(jié)

  • scopedClass 高階函數(shù);
  • React.Fragment
  • 使用&&或者三元表達(dá)式來做條件判斷,一般不用if...else...來寫條件判斷,有點(diǎn)麻煩;
  • ReactDOM.createPortal傳送門,可以使元素脫離當(dāng)前位置到達(dá)你指定的節(jié)點(diǎn)位置;
  • 如何動態(tài)去生成一個(gè)組件;
  • 閉包傳API;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容