本文是筆者寫組件設計的第七篇文章, 今天帶你們實現一個自帶主題且可關閉的Alert組件, 該組件在諸如Antd或者elementUI等第三方組件庫中都會出現,主要用來提供系統的用戶反饋.javascript
之因此會寫組件設計相關的文章,是由於做爲一名前端優秀的前端工程師,面對各類繁瑣而重複的工做,咱們不該該循序漸進的去"辛勤勞動",而是要根據已有前端的開發經驗,總結出一套本身的高效開發的方法.css
前端組件通常會劃分爲以下幾種類型:html
因此咱們在設計組件系統的時候能夠參考如上分類去設計,該分類也是antd, element, zend等主流UI庫的分類方式.前端
若是對於react/vue組件設計原理不熟悉的,能夠參考個人以前寫的組件設計系列文章:vue
筆者已經將組件庫發佈到npm上了, 你們能夠經過npm安裝的方式體驗組件.java
在開始組件設計以前但願你們對css3和js有必定的基礎,並瞭解基本的react/vue語法.咱們先看看實現後的組件效果:node
按照以前筆者總結的組件設計原則,咱們第一步是要確認需求. 一個警告提示(Alert)組件會有以下需求點:react
需求收集好以後,做爲一個有追求的程序員, 會得出以下線框圖: webpack
對於react選手來講,若是沒用typescript,建議你們都用PropTypes, 它是react內置的類型檢測工具,咱們能夠直接在項目中導入. vue有自帶的屬性檢測方式,這裏就不一一介紹了.css3
經過以上需求分析, 咱們發現實現一個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 } = props return <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 複製代碼
有了這個框架,咱們來一步步往裏面實現內容吧.
這幾個功能在框架搭建好以後已經部分實現了,是由於他們都比較簡單,不會牽扯到其餘複雜邏輯.只須要對外暴露屬性並使用屬性便可. 具體實現以下:
function Alert(props) { const { style, closable, closeText, message, description, type, onClose } = props return <div className={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; } } 複製代碼
closable主要是用來讓用戶能手動關閉Alert,onClose是對外暴露的關閉時的方法, 由於不必也不須要向外暴露屬性來讓Alert關閉, 因此最好的方式是在組件內部實現, 咱們會經過useState這個鉤子來處理,代碼以下:
function Alert(props) { const { style, closable, closeText, message, description, type, onClose } = props let [visible, setVisible] = useState(true) const handleColse = () => { setVisible(false) onClose && onClose() } return visible ? <div className={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方法.
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的使用你們能夠本身去官網學習,很是簡單.若是不懂的能夠在評論區提問,筆者看到後會第一時間解答.
咱們能夠經過以下方式使用它:
<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 // 導入xui import { 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 }] ] 複製代碼
npm庫截圖以下:
後續筆者將會繼續實現
等組件, 來複盤筆者多年的組件化之旅.
若是想獲取組件設計系列完整源碼, 或者想學習更多H5遊戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數據可視化等前端知識和實戰,歡迎在公號《趣談前端》加入咱們的技術羣一塊兒學習討論,共同探索前端的邊界。