
前言
本文是筆者寫組件設計的第七篇文章, 今天帶大家實現一個自帶主題且可關閉的Alert組件, 該組件在諸如Antd或者elementUI等第三方組件庫中都會出現,主要用來提供系統的用戶反饋.
之所以會寫組件設計相關的文章,是因為作為一名前端優秀的前端工程師,面對各種繁瑣而重復的工作,我們不應該按部就班的去"辛勤勞動",而是要根據已有前端的開發經驗,總結出一套自己的高效開發的方法.
前端組件一般會劃分為如下幾種類型:
-
通用型組件: 比如Button, Icon等. -
布局型組件: 比如Grid, Layout布局等. -
導航型組件: 比如面包屑Breadcrumb, 下拉菜單Dropdown, 菜單Menu等. -
數據錄入型組件: 比如form表單, Switch開關, Upload文件上傳等. -
數據展示型組件: 比如Avator頭像, Table表格, List列表等. -
反饋型組件: 比如Progress進度條, Drawer抽屜, Modal對話框等. -
其他業務類型
正文

1. 組件設計思路
按照之前筆者總結的組件設計原則,我們第一步是要確認需求. 一個警告提示(Alert)組件會有如下需求點:
-
能控制Alert組件的樣式 -
能控制Alert組件的關閉按鈕是否顯示 -
用戶可以自己輸入提示內容 -
能控制關閉按鈕的文本,或者自定義關閉按鈕 -
支持顯示提示內容的輔助文本 -
內置提供不同類型的警告提示樣式,比如成功, 錯誤, 警告等 -
關閉提示時能提供自定義事件

對于react選手來說,如果沒用typescript,建議大家都用PropTypes, 它是react內置的類型檢測工具,我們可以直接在項目中導入. vue有自帶的屬性檢測方式,這里就不一一介紹了.
通過以上需求分析, 我們發現實現一個Alert非常簡單, 它屬于反饋型組件,所以不會涉及到太多功能.接下來我們就來看看具體實現.
2. 基于react實現一個Alert組件
2.1. Alert組件框架設計
首先我們先根據需求將組件框架寫好,這樣后面寫業務邏輯會更清晰:
import classnames from 'classnames'import styles from './index.less'
/*** 警告提示組件* @param {style} object 更改Alert樣式* @param {closable} bool 是否顯示關閉按鈕, 默認不顯示* @param {closeText} string|reactNode 自定義關閉按鈕* @param {message} string 警告提示內容* @param {description} string 警告提示的輔助性文字* @param {type} string 警告的類型* @param {onClose} func 關閉時觸發的事件*/function Alert(props) {const {style,closable,closeText,message,description,type,onClose} = propsreturn <div className={styles.xAlertWrap}><div className={styles.alertMes}>{ message }</div><div className={styles.alertDesc}>{ description }</div><span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span></div>}export default Alert
有了這個框架,我們就來往里面實現內容吧.
2.2 實現style,closeText,message, description,type
這幾個功能在框架搭建好之后已經部分實現了,是因為他們都比較簡單,不會牽扯到其他復雜邏輯.只需要對外暴露屬性并使用屬性即可. 具體實現如下:
function Alert(props) {const {style,closable,closeText,message,description,type,onClose} = propsreturn <divclassName={classnames(styles.xAlertWrap, styles[type] || styles.warning)}style={{...style}}><div className={styles.alertMes}>{ message }</div><div className={styles.alertDesc}>{ description }</div><span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span></div>}
以上代碼可以發現筆者采用了classnames這個第三方工具, 他可以組合我們的class以實現更靈活的配置. 對于type的實現,我的思路是提前預制好幾種類型樣式, 通過用戶手動配置來匹配到對應的樣式:
.xAlertWrap {box-sizing: border-box;position: relative;padding: 5px 12px;margin-bottom: 16px;border-radius: 3px;&.success {background-color: #f6ffed;border: 1px solid #b7eb8f;}&.info {background-color: #e6f7ff;border: 1px solid #91d5ff;}&.error {background-color: #fffbe6;border: 1px solid #ffe58f;}&.warning {background-color: #fff1f0;border: 1px solid #ffa39e;}}
2.3 實現closable和onClose
closable主要是用來讓用戶能手動關閉Alert,onClose是對外暴露的關閉時的方法, 因為沒必要也不需要向外暴露屬性來讓Alert關閉, 所以最好的方式是在組件內部實現, 我們會通過useState這個鉤子來處理,代碼如下:
function Alert(props) {const {style,closable,closeText,message,description,type,onClose} = propslet [visible, setVisible] = useState(true)const handleColse = () => {setVisible(false)onClose && onClose()}return visible ?<divclassName={classnames(styles.xAlertWrap, styles[type] || styles.warning)}style={{opacity: visible ? '1' : '0',...style}}><div className={styles.alertMes}>{ message }</div><div className={styles.alertDesc}>{ description }</div>{!!closable && <span className={styles.closeBtn} onClick={handleColse}>{ closeText ? closeText : 'x' }</span>}</div> : null}
通過控制visible來控制Alert的出現和消失, 并且當點擊關閉按鈕時能調用外部暴露的onClose方法.
2.4 健壯性支持, 我們采用react提供的propTypes工具:
import PropTypes from 'prop-types'// ...Alert.propTypes = {style: PropTypes.object,closable: PropTypes.bool,closeText: PropTypes.oneOfType([PropTypes.string,PropTypes.element]),message: PropTypes.string,description: PropTypes.string,type: PropTypes.string,onClose: PropTypes.func}
關于prop-types的使用官網上有很詳細的案例,這里說一點就是oneOfType的用法, 它用來支持一個組件可能是多種類型中的一個. 組件完整css代碼如下:
.xAlertWrap {box-sizing: border-box;position: relative;padding: 5px 12px;margin-bottom: 16px;border-radius: 3px;&.success {background-color: #f6ffed;border: 1px solid #b7eb8f;}&.info {background-color: #e6f7ff;border: 1px solid #91d5ff;}&.error {background-color: #fffbe6;border: 1px solid #ffe58f;}&.warning {background-color: #fff1f0;border: 1px solid #ffa39e;}.alertMes {margin-bottom:5px;color: rgba(0, 0, 0, 0.85);font-size: 14px;line-height: 1.5em;}.alertDesc {color: rgba(0, 0, 0, 0.65);font-size: 14px;line-height: 1.5em;word-break: break-all;}.closeBtn {position: absolute;right: 8px;top: 5px;color: rgba(0, 0, 0, 0.4);cursor: pointer;}}
通過以上步驟, 一個健壯的的Alert組件就完成了,關于代碼中的css module和classnames的使用大家可以自己去官網學習,非常簡單.如果不懂的可以在趣談前端技術群里提問,筆者看到后會第一時間解答.
2.5 使用Alert組件
我們可以通過如下方式使用它:
<Alert message="溫馨提示,你忘帶口罩了" /><Alert message="溫馨提示,你注冊成功" type="success" /><Alert message="錯誤提示,你沒洗手了" type="error" /><Alert message="提示: 我們開始吧" type="info" /><Alert message="提示: 我可以關閉了" type="info" closable onClose={() => { alert(111) }} /><Alert message="注冊成功" description="你在本網站已經注冊成功,謝謝您的支持和反饋,多交流真正的技術吧" closable type="success" />
筆者已經將實現過的組件發布到npm上了,大家如果感興趣可以直接用npm安裝后使用,方式如下:
npm i @alex_xu/xui// 導入xuiimport {Button,Skeleton,Empty,Progress,Tag,Switch,Drawer,Badge,Alert} from '@alex_xu/xui'
該組件庫支持按需導入,我們只需要在項目里配置babel-plugin-import即可,具體配置如下:
// .babelrc"plugins": [["import", { "libraryName": "@alex_xu/xui", "style": true }]]

最后
之前筆者已經實現了:
-
modal(模態窗), -
badge(徽標), -
table(表格), -
tooltip(工具提示條), -
Skeleton(骨架屏), -
Message(全局提示), -
form(form表單), -
switch(開關), -
日期/日歷, -
二維碼識別器組件
等組件, 來復盤筆者多年的組件化之旅.
如果想獲取組件設計系列完整源碼, 或者想學習更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數據可視化等前端知識和實戰,歡迎在公號《趣談前端》加入我們的技術群一起學習討論,共同探索前端的邊界。






