確定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;
